mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3129 lines
71 KiB
3129 lines
71 KiB
/*
|
|
* Copyright (C) 2001-2003 FhG Fokus
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* Kamailio is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* Kamailio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*!
|
|
* \file
|
|
* \brief Module interface
|
|
* \ingroup textops
|
|
* Module: \ref textops
|
|
*/
|
|
|
|
/**
|
|
* @defgroup Textops Various text operatoins on messages
|
|
* @brief Kamailio textops module
|
|
*/
|
|
|
|
|
|
|
|
#include "../../action.h"
|
|
#include "../../sr_module.h"
|
|
#include "../../dprint.h"
|
|
#include "../../data_lump.h"
|
|
#include "../../data_lump_rpl.h"
|
|
#include "../../error.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../str.h"
|
|
#include "../../re.h"
|
|
#include "../../lvalue.h"
|
|
#include "../../mod_fix.h"
|
|
#include "../../parser/parse_uri.h"
|
|
#include "../../parser/parse_hname2.h"
|
|
#include "../../parser/parse_methods.h"
|
|
#include "../../parser/parse_content.h"
|
|
#include "../../parser/parse_param.h"
|
|
#include "../../parser/sdp/sdp.h"
|
|
#include "../../parser/sdp/sdp_helpr_funcs.h"
|
|
#include "../../lib/kcore/parse_privacy.h"
|
|
#include "../../msg_translator.h"
|
|
#include "../../ut.h"
|
|
#include "../../dset.h"
|
|
#include "../../lib/kcore/cmpapi.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h> /* for regex */
|
|
#include <regex.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "textops.h"
|
|
#include "txt_var.h"
|
|
#include "api.h"
|
|
|
|
MODULE_VERSION
|
|
|
|
|
|
/* RFC822-conforming dates format:
|
|
|
|
%a -- abbreviated week of day name (locale), %d day of month
|
|
as decimal number, %b abbreviated month name (locale), %Y
|
|
year with century, %T time in 24h notation
|
|
*/
|
|
#define TIME_FORMAT "Date: %a, %d %b %Y %H:%M:%S GMT"
|
|
#define MAX_TIME 64
|
|
|
|
#define AUDIO_STR "audio"
|
|
#define AUDIO_STR_LEN 5
|
|
|
|
|
|
static int search_body_f(struct sip_msg*, char*, char*);
|
|
static int search_hf_f(struct sip_msg*, char*, char*, char*);
|
|
static int replace_f(struct sip_msg*, char*, char*);
|
|
static int replace_body_f(struct sip_msg*, char*, char*);
|
|
static int replace_all_f(struct sip_msg*, char*, char*);
|
|
static int replace_body_all_f(struct sip_msg*, char*, char*);
|
|
static int replace_body_atonce_f(struct sip_msg*, char*, char*);
|
|
static int subst_f(struct sip_msg*, char*, char*);
|
|
static int subst_uri_f(struct sip_msg*, char*, char*);
|
|
static int subst_user_f(struct sip_msg*, char*, char*);
|
|
static int subst_body_f(struct sip_msg*, char*, char*);
|
|
static int subst_hf_f(struct sip_msg*, char*, char*, char*);
|
|
static int filter_body_f(struct sip_msg*, char*, char*);
|
|
static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
|
|
static int search_append_body_f(struct sip_msg*, char*, char*);
|
|
static int append_to_reply_f(struct sip_msg* msg, char* key, char* str);
|
|
static int append_hf_1(struct sip_msg* msg, char* str1, char* str2);
|
|
static int append_hf_2(struct sip_msg* msg, char* str1, char* str2);
|
|
static int insert_hf_1(struct sip_msg* msg, char* str1, char* str2);
|
|
static int insert_hf_2(struct sip_msg* msg, char* str1, char* str2);
|
|
static int append_urihf(struct sip_msg* msg, char* str1, char* str2);
|
|
static int append_time_f(struct sip_msg* msg, char* , char *);
|
|
static int append_time_request_f(struct sip_msg* msg, char* , char *);
|
|
static int set_body_f(struct sip_msg* msg, char*, char *);
|
|
static int set_rpl_body_f(struct sip_msg* msg, char*, char *);
|
|
static int set_multibody_0(struct sip_msg* msg, char*, char *, char *);
|
|
static int set_multibody_1(struct sip_msg* msg, char*, char *, char *);
|
|
static int set_multibody_2(struct sip_msg* msg, char*, char *, char *);
|
|
static int set_multibody_3(struct sip_msg* msg, char*, char *, char *);
|
|
static int append_multibody_2(struct sip_msg* msg, char*, char *);
|
|
static int append_multibody_3(struct sip_msg* msg, char*, char *, char *);
|
|
static int fixup_multibody_f(void** param, int param_no);
|
|
static int remove_multibody_f(struct sip_msg *msg, char *);
|
|
static int get_body_part_raw_f(sip_msg_t* msg, char* ctype, char* ovar);
|
|
static int get_body_part_f(sip_msg_t* msg, char* ctype, char* ovar);
|
|
static int fixup_get_body_part(void** param, int param_no);
|
|
static int is_method_f(struct sip_msg* msg, char* , char *);
|
|
static int has_body_f(struct sip_msg *msg, char *type, char *str2 );
|
|
static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list,
|
|
char* _sep);
|
|
static int cmp_str_f(struct sip_msg *msg, char *str1, char *str2 );
|
|
static int cmp_istr_f(struct sip_msg *msg, char *str1, char *str2 );
|
|
static int starts_with_f(struct sip_msg *msg, char *str1, char *str2 );
|
|
static int remove_hf_re_f(struct sip_msg* msg, char* key, char* foo);
|
|
static int is_present_hf_re_f(struct sip_msg* msg, char* key, char* foo);
|
|
static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 );
|
|
static int fixup_substre(void**, int);
|
|
static int hname_fixup(void** param, int param_no);
|
|
static int free_hname_fixup(void** param, int param_no);
|
|
static int fixup_method(void** param, int param_no);
|
|
static int add_header_fixup(void** param, int param_no);
|
|
static int fixup_body_type(void** param, int param_no);
|
|
static int fixup_in_list(void** param, int param_no);
|
|
static int fixup_free_in_list(void** param, int param_no);
|
|
int fixup_regexpNL_none(void** param, int param_no);
|
|
static int fixup_search_hf(void** param, int param_no);
|
|
static int fixup_subst_hf(void** param, int param_no);
|
|
|
|
static int mod_init(void);
|
|
|
|
static tr_export_t mod_trans[] = {
|
|
{ {"re", sizeof("re")-1}, /* regexp class */
|
|
tr_txt_parse_re },
|
|
|
|
{ { 0, 0 }, 0 }
|
|
};
|
|
|
|
static cmd_export_t cmds[]={
|
|
{"search", (cmd_function)search_f, 1,
|
|
fixup_regexp_null, fixup_free_regexp_null,
|
|
ANY_ROUTE},
|
|
{"search_body", (cmd_function)search_body_f, 1,
|
|
fixup_regexp_null, fixup_free_regexp_null,
|
|
ANY_ROUTE},
|
|
{"search_hf", (cmd_function)search_hf_f, 3,
|
|
fixup_search_hf, 0,
|
|
ANY_ROUTE},
|
|
{"search_append", (cmd_function)search_append_f, 2,
|
|
fixup_regexp_none,fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"search_append_body", (cmd_function)search_append_body_f, 2,
|
|
fixup_regexp_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"replace", (cmd_function)replace_f, 2,
|
|
fixup_regexp_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"replace_body", (cmd_function)replace_body_f, 2,
|
|
fixup_regexp_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"replace_all", (cmd_function)replace_all_f, 2,
|
|
fixup_regexp_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"replace_body_all", (cmd_function)replace_body_all_f,2,
|
|
fixup_regexp_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"replace_body_atonce", (cmd_function)replace_body_atonce_f,2,
|
|
fixup_regexpNL_none, fixup_free_regexp_none,
|
|
ANY_ROUTE},
|
|
{"append_to_reply", (cmd_function)append_to_reply_f, 1,
|
|
fixup_spve_null, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
|
|
{"append_hf", (cmd_function)append_hf_1, 1,
|
|
add_header_fixup, 0,
|
|
ANY_ROUTE},
|
|
{"append_hf", (cmd_function)append_hf_2, 2,
|
|
add_header_fixup, 0,
|
|
ANY_ROUTE},
|
|
{"insert_hf", (cmd_function)insert_hf_1, 1,
|
|
add_header_fixup, 0,
|
|
ANY_ROUTE},
|
|
{"insert_hf", (cmd_function)insert_hf_2, 2,
|
|
add_header_fixup, 0,
|
|
ANY_ROUTE},
|
|
{"append_urihf", (cmd_function)append_urihf, 2,
|
|
fixup_str_str, fixup_free_str_str,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
|
|
{"remove_hf", (cmd_function)remove_hf_f, 1,
|
|
hname_fixup, free_hname_fixup,
|
|
ANY_ROUTE},
|
|
{"remove_hf_re", (cmd_function)remove_hf_re_f, 1,
|
|
fixup_regexp_null, fixup_free_regexp_null,
|
|
ANY_ROUTE},
|
|
{"is_present_hf", (cmd_function)is_present_hf_f, 1,
|
|
hname_fixup, free_hname_fixup,
|
|
ANY_ROUTE},
|
|
{"is_present_hf_re", (cmd_function)is_present_hf_re_f,1,
|
|
fixup_regexp_null, fixup_free_regexp_null,
|
|
ANY_ROUTE},
|
|
{"subst", (cmd_function)subst_f, 1,
|
|
fixup_substre, 0,
|
|
ANY_ROUTE},
|
|
{"subst_uri", (cmd_function)subst_uri_f, 1,
|
|
fixup_substre, 0,
|
|
REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
|
|
{"subst_user", (cmd_function)subst_user_f, 1,
|
|
fixup_substre, 0,
|
|
REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
|
|
{"subst_body", (cmd_function)subst_body_f, 1,
|
|
fixup_substre, 0,
|
|
ANY_ROUTE},
|
|
{"subst_hf", (cmd_function)subst_hf_f, 3,
|
|
fixup_subst_hf, 0,
|
|
ANY_ROUTE},
|
|
{"filter_body", (cmd_function)filter_body_f, 1,
|
|
fixup_str_null, 0,
|
|
ANY_ROUTE},
|
|
{"append_time", (cmd_function)append_time_f, 0,
|
|
0, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
|
|
{"set_body", (cmd_function)set_body_f, 2,
|
|
fixup_spve_spve, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE },
|
|
{"set_reply_body", (cmd_function)set_rpl_body_f, 2,
|
|
fixup_spve_spve, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"is_method", (cmd_function)is_method_f, 1,
|
|
fixup_method, 0,
|
|
ANY_ROUTE},
|
|
{"has_body", (cmd_function)has_body_f, 0,
|
|
0, 0,
|
|
ANY_ROUTE},
|
|
{"has_body", (cmd_function)has_body_f, 1,
|
|
fixup_body_type, 0,
|
|
ANY_ROUTE},
|
|
{"is_privacy", (cmd_function)is_privacy_f, 1,
|
|
fixup_privacy, 0,
|
|
ANY_ROUTE},
|
|
{"in_list", (cmd_function)in_list_f, 3, fixup_in_list,
|
|
fixup_free_in_list,
|
|
ANY_ROUTE},
|
|
{"cmp_str", (cmd_function)cmp_str_f, 2,
|
|
fixup_spve_spve, 0,
|
|
ANY_ROUTE},
|
|
{"cmp_istr", (cmd_function)cmp_istr_f, 2,
|
|
fixup_spve_spve, 0,
|
|
ANY_ROUTE},
|
|
{"starts_with", (cmd_function)starts_with_f, 2,
|
|
fixup_spve_spve, 0,
|
|
ANY_ROUTE},
|
|
{"is_audio_on_hold", (cmd_function)is_audio_on_hold_f, 0,
|
|
0, 0,
|
|
ANY_ROUTE},
|
|
{"append_time_to_request", (cmd_function)append_time_request_f, 0,
|
|
0, 0,
|
|
ANY_ROUTE},
|
|
|
|
{"bind_textops", (cmd_function)bind_textops, 0, 0, 0,
|
|
0},
|
|
{"set_body_multipart", (cmd_function)set_multibody_0, 0,
|
|
0, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"set_body_multipart", (cmd_function)set_multibody_1, 1,
|
|
fixup_spve_null, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"set_body_multipart", (cmd_function)set_multibody_2, 2,
|
|
fixup_spve_spve, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"set_body_multipart", (cmd_function)set_multibody_3, 3,
|
|
fixup_multibody_f, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"append_body_part", (cmd_function)append_multibody_2, 2,
|
|
fixup_spve_spve, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"append_body_part", (cmd_function)append_multibody_3, 3,
|
|
fixup_multibody_f, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"remove_body_part", (cmd_function)remove_multibody_f, 1,
|
|
fixup_spve_null, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
|
|
{"get_body_part_raw", (cmd_function)get_body_part_raw_f, 2,
|
|
fixup_get_body_part, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE },
|
|
{"get_body_part", (cmd_function)get_body_part_f, 2,
|
|
fixup_get_body_part, 0,
|
|
REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE },
|
|
|
|
{0,0,0,0,0,0}
|
|
};
|
|
|
|
|
|
struct module_exports exports= {
|
|
"textops", /* module name*/
|
|
DEFAULT_DLFLAGS, /* dlopen flags */
|
|
cmds, /* exported functions */
|
|
0, /* module parameters */
|
|
0, /* exported statistics */
|
|
0, /* exported MI functions */
|
|
0, /* exported pseudo-variables */
|
|
0, /* extra processes */
|
|
mod_init, /* module initialization function */
|
|
0, /* response function */
|
|
0, /* destroy function */
|
|
0, /* per-child init function */
|
|
};
|
|
|
|
|
|
static int mod_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int mod_register(char *path, int *dlflags, void *p1, void *p2)
|
|
{
|
|
return register_trans_mod(path, mod_trans);
|
|
}
|
|
|
|
static char *get_header(struct sip_msg *msg)
|
|
{
|
|
return msg->buf+msg->first_line.len;
|
|
}
|
|
|
|
|
|
|
|
int search_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
/*we registered only 1 param, so we ignore str2*/
|
|
regmatch_t pmatch;
|
|
|
|
if (regexec((regex_t*) key, msg->buf, 1, &pmatch, 0)!=0) return -1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int search_body_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
str body;
|
|
/*we registered only 1 param, so we ignore str2*/
|
|
regmatch_t pmatch;
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if (body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
if (regexec((regex_t*) key, body.s, 1, &pmatch, 0)!=0) return -1;
|
|
return 1;
|
|
}
|
|
|
|
|
|
int search_append_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
char *begin;
|
|
int off;
|
|
|
|
begin=get_header(msg); /* msg->orig/buf previously .. uri problems */
|
|
off=begin-msg->buf;
|
|
|
|
if (regexec((regex_t*) key, begin, 1, &pmatch, 0)!=0) return -1;
|
|
if (pmatch.rm_so!=-1){
|
|
if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0, 0))==0)
|
|
return -1;
|
|
len=strlen(str2);
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int search_append_body_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
int off;
|
|
str body;
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if (body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
off=body.s-msg->buf;
|
|
|
|
if (regexec((regex_t*) key, body.s, 1, &pmatch, 0)!=0) return -1;
|
|
if (pmatch.rm_so!=-1){
|
|
if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0, 0))==0)
|
|
return -1;
|
|
len=strlen(str2);
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int replace_all_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
char* begin;
|
|
int off;
|
|
int ret;
|
|
int eflags;
|
|
|
|
begin = get_header(msg);
|
|
ret=-1; /* pessimist: we will not find any */
|
|
len=strlen(str2);
|
|
eflags=0; /* match ^ at the beginning of the string*/
|
|
|
|
while (begin<msg->buf+msg->len
|
|
&& regexec((regex_t*) key, begin, 1, &pmatch, eflags)==0) {
|
|
off=begin-msg->buf;
|
|
if (pmatch.rm_so==-1){
|
|
LM_ERR("offset unknown\n");
|
|
return -1;
|
|
}
|
|
if (pmatch.rm_so==pmatch.rm_eo){
|
|
LM_ERR("matched string is empty... invalid regexp?\n");
|
|
return -1;
|
|
}
|
|
if ((l=del_lump(msg, pmatch.rm_so+off,
|
|
pmatch.rm_eo-pmatch.rm_so, 0))==0) {
|
|
LM_ERR("del_lump failed\n");
|
|
return -1;
|
|
}
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
/* new cycle */
|
|
begin=begin+pmatch.rm_eo;
|
|
/* is it still a string start */
|
|
if (*(begin-1)=='\n' || *(begin-1)=='\r')
|
|
eflags&=~REG_NOTBOL;
|
|
else
|
|
eflags|=REG_NOTBOL;
|
|
ret=1;
|
|
} /* while found ... */
|
|
return ret;
|
|
}
|
|
|
|
static int do_replace_body_f(struct sip_msg* msg, char* key, char* str2, int nobol)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
char* begin;
|
|
int off;
|
|
int ret;
|
|
int eflags;
|
|
str body;
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if (body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
begin=body.s;
|
|
ret=-1; /* pessimist: we will not find any */
|
|
len=strlen(str2);
|
|
eflags=0; /* match ^ at the beginning of the string*/
|
|
|
|
while (begin<msg->buf+msg->len
|
|
&& regexec((regex_t*) key, begin, 1, &pmatch, eflags)==0) {
|
|
off=begin-msg->buf;
|
|
if (pmatch.rm_so==-1){
|
|
LM_ERR("offset unknown\n");
|
|
return -1;
|
|
}
|
|
if (pmatch.rm_so==pmatch.rm_eo){
|
|
LM_ERR("matched string is empty... invalid regexp?\n");
|
|
return -1;
|
|
}
|
|
if ((l=del_lump(msg, pmatch.rm_so+off,
|
|
pmatch.rm_eo-pmatch.rm_so, 0))==0) {
|
|
LM_ERR("del_lump failed\n");
|
|
return -1;
|
|
}
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
/* new cycle */
|
|
begin=begin+pmatch.rm_eo;
|
|
/* is it still a string start */
|
|
if (nobol && (*(begin-1)=='\n' || *(begin-1)=='\r'))
|
|
eflags&=~REG_NOTBOL;
|
|
else
|
|
eflags|=REG_NOTBOL;
|
|
ret=1;
|
|
} /* while found ... */
|
|
return ret;
|
|
}
|
|
|
|
static int replace_body_all_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
return do_replace_body_f(msg, key, str2, 1);
|
|
}
|
|
|
|
static int replace_body_atonce_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
return do_replace_body_f(msg, key, str2, 0);
|
|
}
|
|
|
|
static int replace_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
char* begin;
|
|
int off;
|
|
|
|
begin=get_header(msg); /* msg->orig previously .. uri problems */
|
|
|
|
if (regexec((regex_t*) key, begin, 1, &pmatch, 0)!=0) return -1;
|
|
off=begin-msg->buf;
|
|
|
|
if (pmatch.rm_so!=-1){
|
|
if ((l=del_lump(msg, pmatch.rm_so+off,
|
|
pmatch.rm_eo-pmatch.rm_so, 0))==0)
|
|
return -1;
|
|
len=strlen(str2);
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int replace_body_f(struct sip_msg* msg, char* key, char* str2)
|
|
{
|
|
struct lump* l;
|
|
regmatch_t pmatch;
|
|
char* s;
|
|
int len;
|
|
char* begin;
|
|
int off;
|
|
str body;
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if (body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
begin=body.s; /* msg->orig previously .. uri problems */
|
|
|
|
if (regexec((regex_t*) key, begin, 1, &pmatch, 0)!=0) return -1;
|
|
off=begin-msg->buf;
|
|
|
|
if (pmatch.rm_so!=-1){
|
|
if ((l=del_lump(msg, pmatch.rm_so+off,
|
|
pmatch.rm_eo-pmatch.rm_so, 0))==0)
|
|
return -1;
|
|
len=strlen(str2);
|
|
s=pkg_malloc(len);
|
|
if (s==0){
|
|
LM_ERR("memory allocation failure\n");
|
|
return -1;
|
|
}
|
|
memcpy(s, str2, len);
|
|
if (insert_new_lump_after(l, s, len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* sed-perl style re: s/regular expression/replacement/flags */
|
|
static int subst_f(struct sip_msg* msg, char* subst, char* ignored)
|
|
{
|
|
struct lump* l;
|
|
struct replace_lst* lst;
|
|
struct replace_lst* rpl;
|
|
char* begin;
|
|
struct subst_expr* se;
|
|
int off;
|
|
int ret;
|
|
int nmatches;
|
|
|
|
se=(struct subst_expr*)subst;
|
|
begin=get_header(msg); /* start after first line to avoid replacing
|
|
the uri */
|
|
off=begin-msg->buf;
|
|
ret=-1;
|
|
if ((lst=subst_run(se, begin, msg, &nmatches))==0)
|
|
goto error; /* not found */
|
|
for (rpl=lst; rpl; rpl=rpl->next){
|
|
LM_DBG("%s: replacing at offset %d [%.*s] with [%.*s]\n",
|
|
exports.name, rpl->offset+off,
|
|
rpl->size, rpl->offset+off+msg->buf,
|
|
rpl->rpl.len, rpl->rpl.s);
|
|
if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
|
|
goto error;
|
|
/* hack to avoid re-copying rpl, possible because both
|
|
* replace_lst & lumps use pkg_malloc */
|
|
if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0){
|
|
LM_ERR("%s: could not insert new lump\n", exports.name);
|
|
goto error;
|
|
}
|
|
/* hack continued: set rpl.s to 0 so that replace_lst_free will
|
|
* not free it */
|
|
rpl->rpl.s=0;
|
|
rpl->rpl.len=0;
|
|
}
|
|
ret=1;
|
|
error:
|
|
LM_DBG("lst was %p\n", lst);
|
|
if (lst) replace_lst_free(lst);
|
|
if (nmatches<0)
|
|
LM_ERR("%s: subst_run failed\n", exports.name);
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/* sed-perl style re: s/regular expression/replacement/flags, like
|
|
* subst but works on the message uri */
|
|
static int subst_uri_f(struct sip_msg* msg, char* subst, char* ignored)
|
|
{
|
|
char* tmp;
|
|
int len;
|
|
char c;
|
|
struct subst_expr* se;
|
|
str* result;
|
|
|
|
se=(struct subst_expr*)subst;
|
|
if (msg->new_uri.s){
|
|
len=msg->new_uri.len;
|
|
tmp=msg->new_uri.s;
|
|
}else{
|
|
tmp=msg->first_line.u.request.uri.s;
|
|
len =msg->first_line.u.request.uri.len;
|
|
};
|
|
/* ugly hack: 0 s[len], and restore it afterward
|
|
* (our re functions require 0 term strings), we can do this
|
|
* because we always alloc len+1 (new_uri) and for first_line, the
|
|
* message will always be > uri.len */
|
|
c=tmp[len];
|
|
tmp[len]=0;
|
|
result=subst_str(tmp, msg, se, 0); /* pkg malloc'ed result */
|
|
tmp[len]=c;
|
|
if (result){
|
|
LM_DBG("%s match - old uri= [%.*s], new uri= [%.*s]\n",
|
|
exports.name, len, tmp,
|
|
(result->len)?result->len:0,(result->s)?result->s:"");
|
|
if (msg->new_uri.s) pkg_free(msg->new_uri.s);
|
|
msg->new_uri=*result;
|
|
msg->parsed_uri_ok=0; /* reset "use cached parsed uri" flag */
|
|
ruri_mark_new();
|
|
pkg_free(result); /* free str* pointer */
|
|
return 1; /* success */
|
|
}
|
|
return -1; /* false, no subst. made */
|
|
}
|
|
|
|
|
|
|
|
/* sed-perl style re: s/regular expression/replacement/flags, like
|
|
* subst but works on the user part of the uri */
|
|
static int subst_user_f(struct sip_msg* msg, char* subst, char* ignored)
|
|
{
|
|
int rval;
|
|
str* result;
|
|
struct subst_expr* se;
|
|
struct action act;
|
|
struct run_act_ctx h;
|
|
str user;
|
|
char c;
|
|
int nmatches;
|
|
|
|
c=0;
|
|
if (parse_sip_msg_uri(msg)<0){
|
|
return -1; /* error, bad uri */
|
|
}
|
|
if (msg->parsed_uri.user.s==0){
|
|
/* no user in uri */
|
|
user.s="";
|
|
user.len=0;
|
|
}else{
|
|
user=msg->parsed_uri.user;
|
|
c=user.s[user.len];
|
|
user.s[user.len]=0;
|
|
}
|
|
se=(struct subst_expr*)subst;
|
|
result=subst_str(user.s, msg, se, &nmatches);/* pkg malloc'ed result */
|
|
if (c) user.s[user.len]=c;
|
|
if (result == NULL) {
|
|
if (nmatches<0)
|
|
LM_ERR("subst_user(): subst_str() failed\n");
|
|
return -1;
|
|
}
|
|
/* result->s[result->len] = '\0'; --subst_str returns 0-term strings */
|
|
memset(&act, 0, sizeof(act)); /* be on the safe side */
|
|
act.type = SET_USER_T;
|
|
act.val[0].type = STRING_ST;
|
|
act.val[0].u.string = result->s;
|
|
init_run_actions_ctx(&h);
|
|
rval = do_action(&h, &act, msg);
|
|
pkg_free(result->s);
|
|
pkg_free(result);
|
|
return rval;
|
|
}
|
|
|
|
|
|
/* sed-perl style re: s/regular expression/replacement/flags */
|
|
static int subst_body_f(struct sip_msg* msg, char* subst, char* ignored)
|
|
{
|
|
struct lump* l;
|
|
struct replace_lst* lst;
|
|
struct replace_lst* rpl;
|
|
char* begin;
|
|
struct subst_expr* se;
|
|
int off;
|
|
int ret;
|
|
int nmatches;
|
|
str body;
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if (body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
se=(struct subst_expr*)subst;
|
|
begin=body.s;
|
|
|
|
off=begin-msg->buf;
|
|
ret=-1;
|
|
if ((lst=subst_run(se, begin, msg, &nmatches))==0)
|
|
goto error; /* not found */
|
|
for (rpl=lst; rpl; rpl=rpl->next){
|
|
LM_DBG("%s replacing at offset %d [%.*s] with [%.*s]\n",
|
|
exports.name, rpl->offset+off,
|
|
rpl->size, rpl->offset+off+msg->buf,
|
|
rpl->rpl.len, rpl->rpl.s);
|
|
if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
|
|
goto error;
|
|
/* hack to avoid re-copying rpl, possible because both
|
|
* replace_lst & lumps use pkg_malloc */
|
|
if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0){
|
|
LM_ERR("%s could not insert new lump\n",
|
|
exports.name);
|
|
goto error;
|
|
}
|
|
/* hack continued: set rpl.s to 0 so that replace_lst_free will
|
|
* not free it */
|
|
rpl->rpl.s=0;
|
|
rpl->rpl.len=0;
|
|
}
|
|
ret=1;
|
|
error:
|
|
LM_DBG("lst was %p\n", lst);
|
|
if (lst) replace_lst_free(lst);
|
|
if (nmatches<0)
|
|
LM_ERR("%s subst_run failed\n", exports.name);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static inline int find_line_start(char *text, unsigned int text_len,
|
|
char **buf, unsigned int *buf_len)
|
|
{
|
|
char *ch, *start;
|
|
unsigned int len;
|
|
|
|
start = *buf;
|
|
len = *buf_len;
|
|
|
|
while (text_len <= len) {
|
|
if (strncmp(text, start, text_len) == 0) {
|
|
*buf = start;
|
|
*buf_len = len;
|
|
return 1;
|
|
}
|
|
if ((ch = memchr(start, 13, len - 1))) {
|
|
if (*(ch + 1) != 10) {
|
|
LM_ERR("No LF after CR\n");
|
|
return 0;
|
|
}
|
|
len = len - (ch - start + 2);
|
|
start = ch + 2;
|
|
} else {
|
|
LM_ERR("No CRLF found\n");
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* return:
|
|
* 1: multipart
|
|
*/
|
|
static int check_multipart(struct sip_msg *msg)
|
|
{
|
|
int mime;
|
|
|
|
/* the function search for and parses the Content-Type hdr */
|
|
mime = parse_content_type_hdr (msg);
|
|
if(mime<0) {
|
|
LM_ERR("failed to extract content type hdr\n");
|
|
return -1;
|
|
}
|
|
if(mime!=MIMETYPE(MULTIPART,MIXED)) return 0;
|
|
return 1;
|
|
}
|
|
|
|
/* Filters multipart/mixed body by leaving out everything else except
|
|
* first body part of given content type. */
|
|
static int filter_body_f(struct sip_msg* msg, char* _content_type,
|
|
char* ignored)
|
|
{
|
|
char *start;
|
|
unsigned int len;
|
|
str *content_type, body;
|
|
str boundary = {0,0};
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s == 0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len - (int)(body.s - msg->buf);
|
|
if (body.len == 0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
if(check_multipart(msg)!=1) {
|
|
LM_WARN("body not multipart\n");
|
|
return -1;
|
|
}
|
|
if(get_boundary(msg, &boundary)!=0) {
|
|
return -1;
|
|
}
|
|
content_type = (str *)_content_type;
|
|
start = body.s;
|
|
len = body.len;
|
|
|
|
while (find_line_start("Content-Type: ", 14, &start, &len))
|
|
{
|
|
start = start + 14;
|
|
len = len - 14;
|
|
LM_DBG("line: [%.*s]\n", len, start);
|
|
if (len > content_type->len + 2) {
|
|
if (strncasecmp(start, content_type->s, content_type->len)== 0)
|
|
{
|
|
LM_DBG("found content type %.*s\n",
|
|
content_type->len, content_type->s);
|
|
start = start + content_type->len;
|
|
if ((*start != 13) || (*(start + 1) != 10))
|
|
{
|
|
LM_ERR("no CRLF found after content type\n");
|
|
goto err;
|
|
}
|
|
start = start + 2;
|
|
len = len - content_type->len - 2;
|
|
while ((len > 0) && ((*start == 13) || (*start == 10)))
|
|
{
|
|
len = len - 1;
|
|
start = start + 1;
|
|
}
|
|
if (del_lump(msg, body.s - msg->buf, start - body.s, 0)== 0)
|
|
{
|
|
LM_ERR("deleting lump <%.*s> failed\n",
|
|
(int)(start - body.s), body.s);
|
|
goto err;
|
|
}
|
|
if (find_line_start(boundary.s, boundary.len, &start,
|
|
&len))
|
|
{
|
|
/* we need to remove \r\n too */
|
|
if (del_lump(msg, (start-2) - msg->buf, len+2, 0) == 0)
|
|
{
|
|
LM_ERR("deleting lump <%.*s> failed\n", len, start);
|
|
goto err;
|
|
}
|
|
else
|
|
{
|
|
pkg_free(boundary.s);
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LM_ERR("boundary not found after content\n");
|
|
goto err;
|
|
}
|
|
}
|
|
} else {
|
|
goto err;
|
|
}
|
|
}
|
|
err:
|
|
if(boundary.s) pkg_free(boundary.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo)
|
|
{
|
|
struct hdr_field *hf;
|
|
struct lump* l;
|
|
int cnt;
|
|
gparam_p gp;
|
|
|
|
gp = (gparam_p)str_hf;
|
|
cnt=0;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
/* for well known header names str_hf->s will be set to NULL
|
|
during parsing of kamailio.cfg and str_hf->len contains
|
|
the header type */
|
|
if(gp->type==GPARAM_TYPE_INT)
|
|
{
|
|
if (gp->v.i!=hf->type)
|
|
continue;
|
|
} else {
|
|
if (hf->name.len!=gp->v.str.len)
|
|
continue;
|
|
if (cmp_hdrname_str(&hf->name, &gp->v.str)!=0)
|
|
continue;
|
|
}
|
|
l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
|
|
if (l==0) {
|
|
LM_ERR("no memory\n");
|
|
return -1;
|
|
}
|
|
cnt++;
|
|
}
|
|
return cnt==0 ? -1 : 1;
|
|
}
|
|
|
|
static int remove_hf_re_f(struct sip_msg* msg, char* key, char* foo)
|
|
{
|
|
struct hdr_field *hf;
|
|
struct lump* l;
|
|
int cnt;
|
|
regex_t *re;
|
|
char c;
|
|
regmatch_t pmatch;
|
|
|
|
re = (regex_t*)key;
|
|
cnt=0;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next)
|
|
{
|
|
c = hf->name.s[hf->name.len];
|
|
hf->name.s[hf->name.len] = '\0';
|
|
if (regexec(re, hf->name.s, 1, &pmatch, 0)!=0)
|
|
{
|
|
hf->name.s[hf->name.len] = c;
|
|
continue;
|
|
}
|
|
hf->name.s[hf->name.len] = c;
|
|
l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
|
|
if (l==0)
|
|
{
|
|
LM_ERR("cannot remove header\n");
|
|
return -1;
|
|
}
|
|
cnt++;
|
|
}
|
|
|
|
return cnt==0 ? -1 : 1;
|
|
}
|
|
|
|
static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo)
|
|
{
|
|
struct hdr_field *hf;
|
|
gparam_p gp;
|
|
|
|
gp = (gparam_p)str_hf;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
if(gp->type==GPARAM_TYPE_INT)
|
|
{
|
|
if (gp->v.i!=hf->type)
|
|
continue;
|
|
} else {
|
|
if (hf->name.len!=gp->v.str.len)
|
|
continue;
|
|
if (cmp_hdrname_str(&hf->name,&gp->v.str)!=0)
|
|
continue;
|
|
}
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int is_present_hf_re_f(struct sip_msg* msg, char* key, char* foo)
|
|
{
|
|
struct hdr_field *hf;
|
|
regex_t *re;
|
|
regmatch_t pmatch;
|
|
char c;
|
|
|
|
re = (regex_t*)key;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next)
|
|
{
|
|
c = hf->name.s[hf->name.len];
|
|
hf->name.s[hf->name.len] = '\0';
|
|
if (regexec(re, hf->name.s, 1, &pmatch, 0)!=0)
|
|
{
|
|
hf->name.s[hf->name.len] = c;
|
|
continue;
|
|
}
|
|
hf->name.s[hf->name.len] = c;
|
|
return 1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int fixup_substre(void** param, int param_no)
|
|
{
|
|
struct subst_expr* se;
|
|
str subst;
|
|
|
|
LM_DBG("%s module -- fixing %s\n", exports.name, (char*)(*param));
|
|
if (param_no!=1) return 0;
|
|
subst.s=*param;
|
|
subst.len=strlen(*param);
|
|
se=subst_parser(&subst);
|
|
if (se==0){
|
|
LM_ERR("%s: bad subst. re %s\n", exports.name,
|
|
(char*)*param);
|
|
return E_BAD_RE;
|
|
}
|
|
/* don't free string -- needed for specifiers */
|
|
/* pkg_free(*param); */
|
|
/* replace it with the compiled subst. re */
|
|
*param=se;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int append_time_f(struct sip_msg* msg, char* p1, char *p2)
|
|
{
|
|
|
|
|
|
size_t len;
|
|
char time_str[MAX_TIME];
|
|
time_t now;
|
|
struct tm *bd_time;
|
|
|
|
now=time(0);
|
|
|
|
bd_time=gmtime(&now);
|
|
if (bd_time==NULL) {
|
|
LM_ERR("gmtime failed\n");
|
|
return -1;
|
|
}
|
|
|
|
len=strftime(time_str, MAX_TIME, TIME_FORMAT, bd_time);
|
|
if (len>MAX_TIME-2 || len==0) {
|
|
LM_ERR("unexpected time length\n");
|
|
return -1;
|
|
}
|
|
|
|
time_str[len]='\r';
|
|
time_str[len+1]='\n';
|
|
|
|
|
|
if (add_lump_rpl(msg, time_str, len+2, LUMP_RPL_HDR)==0)
|
|
{
|
|
LM_ERR("unable to add lump\n");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int append_time_request_f(struct sip_msg* msg, char* p1, char *p2)
|
|
{
|
|
str time_str = {0, 0};
|
|
time_t now;
|
|
struct tm *bd_time;
|
|
struct hdr_field *hf = msg->headers;
|
|
struct lump *anchor = anchor_lump(msg, hf->name.s + hf->len - msg->buf, 0, 0);
|
|
|
|
now=time(0);
|
|
|
|
bd_time=gmtime(&now);
|
|
if (bd_time==NULL) {
|
|
LM_ERR("gmtime failed\n");
|
|
goto error;
|
|
}
|
|
|
|
time_str.s = pkg_malloc(MAX_TIME);
|
|
if(time_str.s==NULL) {
|
|
LM_ERR("no more pkg memory\n");
|
|
goto error;
|
|
}
|
|
time_str.len=strftime(time_str.s, MAX_TIME, TIME_FORMAT, bd_time);
|
|
if (time_str.len>MAX_TIME-2 || time_str.len==0) {
|
|
LM_ERR("unexpected time length\n");
|
|
goto error;
|
|
}
|
|
|
|
time_str.s[time_str.len++]='\r';
|
|
time_str.s[time_str.len++]='\n';
|
|
|
|
if (anchor == NULL)
|
|
{
|
|
LM_ERR("Problem with getting anchor");
|
|
goto error;
|
|
}
|
|
|
|
if (insert_new_lump_after(anchor, time_str.s, time_str.len, 0) == 0)
|
|
{
|
|
LM_ERR("unable to add lump\n");
|
|
goto error;
|
|
}
|
|
|
|
return 1;
|
|
error:
|
|
if (time_str.s != NULL)
|
|
pkg_free(time_str.s);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int set_body_f(struct sip_msg* msg, char* p1, char* p2)
|
|
{
|
|
struct lump *anchor;
|
|
char* buf;
|
|
int len;
|
|
char* value_s;
|
|
int value_len;
|
|
str body = {0,0};
|
|
str nb = {0,0};
|
|
str nc = {0,0};
|
|
|
|
if(p1==0 || p2==0)
|
|
{
|
|
LM_ERR("invalid parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
|
|
{
|
|
LM_ERR("unable to get p1\n");
|
|
return -1;
|
|
}
|
|
if(nb.s==NULL || nb.len == 0)
|
|
{
|
|
LM_ERR("invalid body parameter\n");
|
|
return -1;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
|
|
{
|
|
LM_ERR("unable to get p2\n");
|
|
return -1;
|
|
}
|
|
if(nc.s==NULL || nc.len == 0)
|
|
{
|
|
LM_ERR("invalid content-type parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
body.len = 0;
|
|
body.s = get_body(msg);
|
|
if (body.s==0)
|
|
{
|
|
LM_ERR("malformed sip message\n");
|
|
return -1;
|
|
}
|
|
|
|
del_nonshm_lump( &(msg->body_lumps) );
|
|
msg->body_lumps = NULL;
|
|
|
|
if (msg->content_length)
|
|
{
|
|
body.len = get_content_length( msg );
|
|
if(body.len > 0)
|
|
{
|
|
if(body.s+body.len>msg->buf+msg->len)
|
|
{
|
|
LM_ERR("invalid content length: %d\n", body.len);
|
|
return -1;
|
|
}
|
|
if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0)
|
|
{
|
|
LM_ERR("cannot delete existing body");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
|
|
|
|
if (anchor == 0)
|
|
{
|
|
LM_ERR("failed to get anchor\n");
|
|
return -1;
|
|
}
|
|
|
|
if (msg->content_length==0)
|
|
{
|
|
/* need to add Content-Length */
|
|
len = nb.len;
|
|
value_s=int2str(len, &value_len);
|
|
LM_DBG("content-length: %d (%s)\n", value_len, value_s);
|
|
|
|
len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
|
|
buf=pkg_malloc(sizeof(char)*(len));
|
|
|
|
if (buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return -1;
|
|
}
|
|
|
|
memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
|
|
memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
|
|
memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
|
|
if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to insert content-length lump\n");
|
|
pkg_free(buf);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* add content-type */
|
|
if(msg->content_type==NULL || msg->content_type->body.len!=nc.len
|
|
|| strncmp(msg->content_type->body.s, nc.s, nc.len)!=0)
|
|
{
|
|
if(msg->content_type!=NULL)
|
|
if(del_lump(msg, msg->content_type->name.s-msg->buf,
|
|
msg->content_type->len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to delete content type\n");
|
|
return -1;
|
|
}
|
|
value_len = nc.len;
|
|
len=sizeof("Content-Type: ") - 1 + value_len + CRLF_LEN;
|
|
buf=pkg_malloc(sizeof(char)*(len));
|
|
|
|
if (buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return -1;
|
|
}
|
|
memcpy(buf, "Content-Type: ", sizeof("Content-Type: ") - 1);
|
|
memcpy(buf+sizeof("Content-Type: ") - 1, nc.s, value_len);
|
|
memcpy(buf+sizeof("Content-Type: ") - 1 + value_len, CRLF, CRLF_LEN);
|
|
if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to insert content-type lump\n");
|
|
pkg_free(buf);
|
|
return -1;
|
|
}
|
|
}
|
|
anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
|
|
|
|
if (anchor == 0)
|
|
{
|
|
LM_ERR("failed to get body anchor\n");
|
|
return -1;
|
|
}
|
|
|
|
buf=pkg_malloc(sizeof(char)*(nb.len));
|
|
if (buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return -1;
|
|
}
|
|
memcpy(buf, nb.s, nb.len);
|
|
if (insert_new_lump_after(anchor, buf, nb.len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to insert body lump\n");
|
|
pkg_free(buf);
|
|
return -1;
|
|
}
|
|
LM_DBG("new body: [%.*s]", nb.len, nb.s);
|
|
return 1;
|
|
}
|
|
|
|
static int set_rpl_body_f(struct sip_msg* msg, char* p1, char* p2)
|
|
{
|
|
char* buf;
|
|
int len;
|
|
int value_len;
|
|
str nb = {0,0};
|
|
str nc = {0,0};
|
|
|
|
if(p1==0 || p2==0)
|
|
{
|
|
LM_ERR("invalid parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
|
|
{
|
|
LM_ERR("unable to get p1\n");
|
|
return -1;
|
|
}
|
|
if(nb.s==NULL || nb.len == 0)
|
|
{
|
|
LM_ERR("invalid body parameter\n");
|
|
return -1;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
|
|
{
|
|
LM_ERR("unable to get p2\n");
|
|
return -1;
|
|
}
|
|
if(nc.s==NULL || nc.len == 0)
|
|
{
|
|
LM_ERR("invalid content-type parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
/* add content-type */
|
|
value_len = nc.len;
|
|
len=sizeof("Content-Type: ") - 1 + value_len + CRLF_LEN;
|
|
buf=pkg_malloc(sizeof(char)*(len));
|
|
|
|
if (buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return -1;
|
|
}
|
|
memcpy(buf, "Content-Type: ", sizeof("Content-Type: ") - 1);
|
|
memcpy(buf+sizeof("Content-Type: ") - 1, nc.s, value_len);
|
|
memcpy(buf+sizeof("Content-Type: ") - 1 + value_len, CRLF, CRLF_LEN);
|
|
if (add_lump_rpl(msg, buf, len, LUMP_RPL_HDR) == 0)
|
|
{
|
|
LM_ERR("failed to insert content-type lump\n");
|
|
pkg_free(buf);
|
|
return -1;
|
|
}
|
|
pkg_free(buf);
|
|
|
|
if (add_lump_rpl( msg, nb.s, nb.len, LUMP_RPL_BODY)==0) {
|
|
LM_ERR("cannot add body lump\n");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static str* generate_boundary(str *txt, str *content_type,
|
|
str *content_disposition, str *delimiter, unsigned int initial)
|
|
{
|
|
unsigned int i = 0;
|
|
str cth = {"Content-Type: ", 14};
|
|
str cdh = {"Content-Disposition: ", 21};
|
|
str* n;
|
|
unsigned int flag = 0;
|
|
|
|
if(txt==NULL||txt->len==0
|
|
||content_type==NULL||content_type->len==0
|
|
||delimiter==NULL||delimiter->len==0)
|
|
{
|
|
LM_ERR("invalid parameters\n");
|
|
return NULL;
|
|
}
|
|
if (delimiter->s[0] == '-') {
|
|
LM_ERR("delimiter with initial '-'. Invalid parameter.\n");
|
|
return NULL;
|
|
}
|
|
n = pkg_malloc(sizeof(str));
|
|
if(n==NULL)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return NULL;
|
|
}
|
|
n->len = delimiter->len + 2 + CRLF_LEN;
|
|
if(initial) n->len = 2*n->len;
|
|
if(strncmp("\r\n\r\n", txt->s+txt->len-4,4)!=0)
|
|
{
|
|
n->len = n->len + CRLF_LEN;
|
|
flag = 1;
|
|
LM_DBG("adding final CRLF+CRLF\n");
|
|
}
|
|
n->len=n->len + cth.len + content_type->len + 2*CRLF_LEN;
|
|
if(content_disposition->len>0)
|
|
{
|
|
n->len = n->len + cdh.len + content_disposition->len + CRLF_LEN;
|
|
}
|
|
n->len = n->len + txt->len;
|
|
n->s = pkg_malloc(sizeof(char)*(n->len));
|
|
if(n->s==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
pkg_free(n);
|
|
return NULL;
|
|
}
|
|
memset(n->s, 0, sizeof(char)*n->len);
|
|
if(initial)
|
|
{
|
|
memcpy(n->s, "--", 2); i=2;
|
|
memcpy(n->s+i, delimiter->s, delimiter->len); i=i+delimiter->len;
|
|
memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
|
}
|
|
|
|
memcpy(n->s+i, cth.s, cth.len); i=i+cth.len;
|
|
memcpy(n->s+i, content_type->s, content_type->len); i=i+content_type->len;
|
|
memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
|
|
|
if(content_disposition->len>0)
|
|
{
|
|
memcpy(n->s+i, cdh.s, cdh.len); i=i+cdh.len;
|
|
memcpy(n->s+i, content_disposition->s, content_disposition->len);
|
|
i=i+content_disposition->len;
|
|
memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
|
}
|
|
memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
|
|
|
memcpy(n->s+i, txt->s, txt->len); i=i+txt->len;
|
|
if(flag) { memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN; }
|
|
|
|
memcpy(n->s+i, "--", 2); i=i+2;
|
|
memcpy(n->s+i, delimiter->s, delimiter->len); i=i+delimiter->len;
|
|
memcpy(n->s+i, CRLF, CRLF_LEN); i=i+CRLF_LEN;
|
|
|
|
if(i!=n->len)
|
|
{
|
|
LM_ERR("out of bounds\n");
|
|
}
|
|
return n;
|
|
}
|
|
|
|
int set_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
|
{
|
|
struct lump *anchor;
|
|
char* buf = NULL;
|
|
int len;
|
|
char* value_s;
|
|
int value_len;
|
|
str body = {0,0};
|
|
str nb = {0,0};
|
|
str oc = {0,0};
|
|
str cd = {0,0};
|
|
str delimiter = {0,0};
|
|
str default_delimiter = {"unique-boundary-1", 17};
|
|
str nc = {0,0};
|
|
str cth = {"Content-Type: ", 14};
|
|
str* nbb = NULL;
|
|
unsigned int convert = 0;
|
|
fparam_t header;
|
|
header.orig = NULL;
|
|
header.type = FPARAM_STR;
|
|
header.v.str.s = "Mime-Version: 1.0\r\n";
|
|
header.v.str.len = 19;
|
|
|
|
if(p3==0)
|
|
{
|
|
delimiter.s = default_delimiter.s;
|
|
delimiter.len = default_delimiter.len;
|
|
}
|
|
else
|
|
{
|
|
if(fixup_get_svalue(msg, (gparam_p)p3, &delimiter)!=0)
|
|
{
|
|
LM_ERR("unable to get p3\n");
|
|
return -1;
|
|
}
|
|
if(delimiter.s==NULL || delimiter.len == 0)
|
|
{
|
|
LM_ERR("invalid boundary parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
LM_DBG("delimiter<%d>:[%.*s]\n", delimiter.len, delimiter.len, delimiter.s);
|
|
if(p1==0 || p2==0)
|
|
{
|
|
if(check_multipart(msg)==1) {
|
|
LM_WARN("body is already multipart. Do nothing\n");
|
|
return -1;
|
|
}
|
|
convert = 1;
|
|
}
|
|
else
|
|
{
|
|
if(fixup_get_svalue(msg, (gparam_p)p1, &nb)!=0)
|
|
{
|
|
LM_ERR("unable to get p1\n");
|
|
return -1;
|
|
}
|
|
if(nb.s==NULL || nb.len == 0)
|
|
{
|
|
LM_ERR("invalid body parameter\n");
|
|
return -1;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)p2, &oc)!=0)
|
|
{
|
|
LM_ERR("unable to get p2\n");
|
|
return -1;
|
|
}
|
|
if(oc.s==NULL || oc.len==0)
|
|
{
|
|
LM_ERR("invalid content-type parameter\n");
|
|
return -1;
|
|
}
|
|
if(check_multipart(msg)==1) {
|
|
convert = -1;
|
|
}
|
|
}
|
|
|
|
body.len = 0;
|
|
body.s = get_body(msg);
|
|
if(body.s==0)
|
|
{
|
|
LM_ERR("malformed sip message\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
|
|
del_nonshm_lump( &(msg->body_lumps) );
|
|
msg->body_lumps = NULL;
|
|
|
|
if(msg->content_length)
|
|
{
|
|
if(body.len > 0)
|
|
{
|
|
if(body.s+body.len>msg->buf+msg->len)
|
|
{
|
|
LM_ERR("invalid content length: %d\n", body.len);
|
|
return -1;
|
|
}
|
|
if(convert==1)
|
|
{
|
|
/* need to copy body */
|
|
nb.s=pkg_malloc(sizeof(char)*body.len);
|
|
if (nb.s==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
return -1;
|
|
}
|
|
memcpy(nb.s, body.s, body.len);
|
|
nb.len = body.len;
|
|
if(msg->content_type!=NULL && msg->content_type->body.s!=NULL)
|
|
{
|
|
oc.len = msg->content_type->body.len;
|
|
oc.s=pkg_malloc(sizeof(char)*oc.len);
|
|
if (oc.s==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
goto error;
|
|
}
|
|
memcpy(oc.s, msg->content_type->body.s, oc.len);
|
|
}
|
|
}
|
|
if(del_lump(msg, body.s-msg->buf, body.len, 0) == 0)
|
|
{
|
|
LM_ERR("cannot delete existing body");
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
anchor = anchor_lump(msg, msg->unparsed-msg->buf, 0, 0);
|
|
if(anchor==0)
|
|
{
|
|
LM_ERR("failed to get anchor\n");
|
|
goto error;
|
|
}
|
|
|
|
/* get initial boundary */
|
|
nbb = generate_boundary(&nb, &oc, &cd, &delimiter, 1);
|
|
if(nbb==NULL)
|
|
{
|
|
LM_ERR("couldn't create initial boundary\n");
|
|
goto error;
|
|
}
|
|
|
|
if(msg->content_length==0)
|
|
{
|
|
/* need to add Content-Length */
|
|
len = nbb->len;
|
|
value_s=int2str(len, &value_len);
|
|
|
|
len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
|
|
buf=pkg_malloc(sizeof(char)*len);
|
|
|
|
if (buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
goto error;
|
|
}
|
|
|
|
memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
|
|
memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
|
|
memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
|
|
if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to insert content-length lump\n");
|
|
goto error;
|
|
}
|
|
buf = NULL;
|
|
}
|
|
|
|
if(convert!=-1)
|
|
{
|
|
/* set new content type with delimiter */
|
|
nc.len = delimiter.len + 27;
|
|
nc.s = pkg_malloc(sizeof(char)*nc.len);
|
|
memcpy(nc.s, "multipart/mixed;boundary=\"", 26);
|
|
memcpy(nc.s+26, delimiter.s, delimiter.len);
|
|
nc.s[26+delimiter.len] = '"';
|
|
LM_DBG("content-type<%d>:[%.*s]\n", nc.len, nc.len, nc.s);
|
|
/* add content-type */
|
|
if(msg->content_type==NULL || msg->content_type->body.len!=nc.len
|
|
|| strncmp(msg->content_type->body.s, nc.s, nc.len)!=0)
|
|
{
|
|
if(msg->content_type!=NULL)
|
|
if(del_lump(msg, msg->content_type->name.s-msg->buf,
|
|
msg->content_type->len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to delete content type\n");
|
|
goto error;
|
|
}
|
|
value_len = nc.len;
|
|
len = cth.len + value_len + CRLF_LEN;
|
|
buf = pkg_malloc(sizeof(char)*len);
|
|
|
|
if(buf==0)
|
|
{
|
|
LM_ERR("out of pkg memory\n");
|
|
goto error;
|
|
}
|
|
memcpy(buf, cth.s, cth.len);
|
|
memcpy(buf + cth.len, nc.s, value_len);
|
|
memcpy(buf + cth.len + value_len, CRLF, CRLF_LEN);
|
|
if (insert_new_lump_after(anchor, buf, len, 0) == 0)
|
|
{
|
|
LM_ERR("failed to insert content-type lump\n");
|
|
goto error;
|
|
}
|
|
buf = NULL;
|
|
}
|
|
/* add Mime-Version header */
|
|
if(add_hf_helper(msg, 0, 0, &header, 0, 0)<0)
|
|
{
|
|
LM_ERR("failed to add Mime-Version header\n");
|
|
goto error;
|
|
}
|
|
}
|
|
anchor = anchor_lump(msg, body.s - msg->buf, 0, 0);
|
|
if(anchor==0)
|
|
{
|
|
LM_ERR("failed to get body anchor\n");
|
|
goto error;
|
|
}
|
|
|
|
if(insert_new_lump_after(anchor, nbb->s, nbb->len, 0)==0)
|
|
{
|
|
LM_ERR("failed to insert body lump\n");
|
|
goto error;
|
|
}
|
|
pkg_free(nbb);
|
|
if(nc.s!=NULL) pkg_free(nc.s);
|
|
if(convert && nb.s!=NULL) pkg_free(nb.s);
|
|
if(convert && oc.s!=NULL) pkg_free(oc.s);
|
|
LM_DBG("set flag FL_BODY_MULTIPART\n");
|
|
msg->msg_flags |= FL_BODY_MULTIPART;
|
|
return 1;
|
|
|
|
error:
|
|
if(nbb!=NULL) { pkg_free(nbb->s); pkg_free(nbb); }
|
|
if(nc.s!=NULL) pkg_free(nc.s);
|
|
if(buf!=NULL) pkg_free(buf);
|
|
if(convert && nb.s!=NULL) pkg_free(nb.s);
|
|
if(convert && oc.s!=NULL) pkg_free(oc.s);
|
|
return -1;
|
|
}
|
|
|
|
static int set_multibody_0(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
|
{
|
|
return set_multibody_helper(msg, NULL, NULL, NULL);
|
|
}
|
|
|
|
static int set_multibody_1(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
|
{
|
|
return set_multibody_helper(msg, NULL, NULL, p1);
|
|
}
|
|
|
|
static int set_multibody_2(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
|
{
|
|
return set_multibody_helper(msg, p1, p2, NULL);
|
|
}
|
|
|
|
static int set_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
|
|
{
|
|
return set_multibody_helper(msg, p1, p2, p3);
|
|
}
|
|
|
|
int append_multibody_helper(struct sip_msg* msg, char* p1, char* p2, char* p3)
|
|
{
|
|
struct lump *l;
|
|
int off;
|
|
str body = {0,0};
|
|
str nc = {0,0};
|
|
str cd = {0,0};
|
|
str txt = {0,0};
|
|
str* nbb = NULL;
|
|
str delimiter = {0,0};
|
|
|
|
if(p1==0 || p2==0)
|
|
{
|
|
LM_ERR("invalid parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)p1, &txt)!=0)
|
|
{
|
|
LM_ERR("unable to get p1\n");
|
|
return -1;
|
|
}
|
|
if(txt.s==NULL || txt.len==0)
|
|
{
|
|
LM_ERR("invalid body parameter\n");
|
|
return -1;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)p2, &nc)!=0)
|
|
{
|
|
LM_ERR("unable to get p2\n");
|
|
return -1;
|
|
}
|
|
if(nc.s==NULL || nc.len==0)
|
|
{
|
|
LM_ERR("invalid content-type parameter\n");
|
|
return -1;
|
|
}
|
|
if(p3!=NULL)
|
|
{
|
|
if(fixup_get_svalue(msg, (gparam_p)p3, &cd)!=0)
|
|
{
|
|
LM_ERR("unable to get p3\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
body.s = get_body(msg);
|
|
if(body.s==0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len -(int)(body.s-msg->buf);
|
|
if(body.len==0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
off=body.s-msg->buf;
|
|
if((l=anchor_lump(msg, off+body.len, 0, 0))==0)
|
|
{
|
|
LM_ERR("WTF\n");
|
|
return -1;
|
|
}
|
|
/* get delimiter no initial -- */
|
|
if(get_mixed_part_delimiter(&msg->content_type->body, &delimiter) < 0) {
|
|
LM_ERR("Cannot get boundary. Is body multipart?\n");
|
|
return -1;
|
|
}
|
|
nbb = generate_boundary(&txt, &nc, &cd, &delimiter, 0);
|
|
if(nbb==NULL)
|
|
{
|
|
LM_ERR("couldn't create initial boundary\n");
|
|
return -1;
|
|
}
|
|
if(insert_new_lump_after(l, nbb->s, nbb->len, 0)==0){
|
|
LM_ERR("could not insert new lump\n");
|
|
pkg_free(nbb->s); pkg_free(nbb);
|
|
return -1;
|
|
}
|
|
pkg_free(nbb);
|
|
if(!(msg->msg_flags&FL_BODY_MULTIPART))
|
|
{
|
|
LM_DBG("set flag FL_BODY_MULTIPART\n");
|
|
msg->msg_flags |= FL_BODY_MULTIPART;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int append_multibody_2(struct sip_msg* msg, char* p1, char* p2)
|
|
{
|
|
return append_multibody_helper(msg, p1, p2, NULL);
|
|
}
|
|
|
|
static int append_multibody_3(struct sip_msg* msg, char* p1, char* p2, char *p3)
|
|
{
|
|
return append_multibody_helper(msg, p1, p2, p3);
|
|
}
|
|
|
|
static int fixup_multibody_f(void** param, int param_no)
|
|
{
|
|
int ret;
|
|
fparam_t* fp;
|
|
|
|
if(param_no<=3){
|
|
if((ret=fix_param_types(FPARAM_PVE, param))<0){
|
|
ERR("Cannot convert function parameter %d to spve \n",
|
|
param_no);
|
|
return E_UNSPEC;
|
|
} else {
|
|
fp=(fparam_t*)*param;
|
|
if((ret==0) && (fp->v.pve->spec==0
|
|
|| fp->v.pve->spec->getf==0)){
|
|
fparam_free_restore(param);
|
|
return fix_param_types(FPARAM_STR, param);
|
|
} else if(ret==1)
|
|
return fix_param_types(FPARAM_STR, param);
|
|
return ret;
|
|
}
|
|
} else {
|
|
LM_ERR("wrong number of parameters\n");
|
|
return E_UNSPEC;
|
|
}
|
|
}
|
|
|
|
static inline int get_line(char *s, int len)
|
|
{
|
|
char *ch;
|
|
|
|
if ((ch = memchr(s, 13, len))) {
|
|
if (*(ch + 1) != 10) {
|
|
LM_ERR("No LF after CR\n");
|
|
return 0;
|
|
}
|
|
return ch - s + 2;
|
|
} else {
|
|
LM_ERR("No CRLF found\n");
|
|
return len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int remove_multibody_f(struct sip_msg* msg, char* p1)
|
|
{
|
|
char *start, *end;
|
|
unsigned int len, t;
|
|
str content_type, body;
|
|
str boundary = {0,0};
|
|
|
|
if(p1==0)
|
|
{
|
|
LM_ERR("invalid parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)p1, &content_type)!=0)
|
|
{
|
|
LM_ERR("unable to get p1\n");
|
|
return -1;
|
|
}
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s == 0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len - (int)(body.s - msg->buf);
|
|
if (body.len == 0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
if(get_boundary(msg, &boundary)!=0) {
|
|
LM_ERR("Cannot get boundary. Is body multipart?\n");
|
|
return -1;
|
|
}
|
|
|
|
start = body.s;
|
|
len = body.len;
|
|
|
|
while (find_line_start("Content-Type: ", 14, &start, &len))
|
|
{
|
|
end = start + 14;
|
|
len = len - 14;
|
|
if (len > (content_type.len + 2)) {
|
|
if (strncasecmp(end, content_type.s, content_type.len)== 0)
|
|
{
|
|
LM_DBG("found content type %.*s\n",
|
|
content_type.len, content_type.s);
|
|
end = end + content_type.len;
|
|
if ((*end != 13) || (*(end + 1) != 10))
|
|
{
|
|
LM_ERR("no CRLF found after content type\n");
|
|
goto err;
|
|
}
|
|
end = end + 2;
|
|
len = len - content_type.len - 2;
|
|
if (find_line_start(boundary.s, boundary.len, &end,
|
|
&len))
|
|
{
|
|
LM_DBG("found boundary %.*s\n", boundary.len, boundary.s);
|
|
end = end + boundary.len;
|
|
len = len - boundary.len;
|
|
if (!(t = get_line(end, len))) goto err;
|
|
end += t; len = end-start;
|
|
if (del_lump(msg, start - msg->buf, len, 0) == 0)
|
|
{
|
|
LM_ERR("deleting lump <%.*s> failed\n", len, start);
|
|
goto err;
|
|
}
|
|
pkg_free(boundary.s);
|
|
if(!(msg->msg_flags&FL_BODY_MULTIPART))
|
|
{
|
|
LM_DBG("set flag FL_BODY_MULTIPART\n");
|
|
msg->msg_flags |= FL_BODY_MULTIPART;
|
|
}
|
|
return 1;
|
|
}
|
|
LM_ERR("boundary not found after content\n");
|
|
goto err;
|
|
}
|
|
start = end;
|
|
}
|
|
else goto err;
|
|
}
|
|
err:
|
|
pkg_free(boundary.s);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int get_body_part_helper(sip_msg_t* msg, char* ctype, char* ovar, int mode)
|
|
{
|
|
char *start, *end, *bstart;
|
|
char *body_headers_end;
|
|
unsigned int len, t;
|
|
str content_type, body;
|
|
str boundary = {0,0};
|
|
pv_spec_t *dst;
|
|
pv_value_t val;
|
|
|
|
if(ctype==0) {
|
|
LM_ERR("invalid parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_t*)ctype, &content_type)!=0) {
|
|
LM_ERR("unable to get content type\n");
|
|
return -1;
|
|
}
|
|
|
|
body.s = get_body(msg);
|
|
if (body.s == 0) {
|
|
LM_ERR("failed to get the message body\n");
|
|
return -1;
|
|
}
|
|
body.len = msg->len - (int)(body.s - msg->buf);
|
|
if (body.len == 0) {
|
|
LM_DBG("message body has zero length\n");
|
|
return -1;
|
|
}
|
|
|
|
if(get_boundary(msg, &boundary)!=0) {
|
|
LM_ERR("Cannot get boundary. Is body multipart?\n");
|
|
return -1;
|
|
}
|
|
|
|
start = body.s;
|
|
len = body.len;
|
|
|
|
/* note: header body can follow just after name: - fixit */
|
|
while (find_line_start("Content-Type: ", 14, &start, &len))
|
|
{
|
|
end = start + 14;
|
|
len = len - 14;
|
|
if (len > (content_type.len + 2)) {
|
|
if (strncasecmp(end, content_type.s, content_type.len)== 0)
|
|
{
|
|
LM_DBG("found content type %.*s\n",
|
|
content_type.len, content_type.s);
|
|
end = end + content_type.len;
|
|
if ((*end != 13) || (*(end + 1) != 10))
|
|
{
|
|
LM_ERR("no CRLF found after content type\n");
|
|
goto err;
|
|
}
|
|
end = end + 2;
|
|
len = len - content_type.len - 2;
|
|
body_headers_end = end;
|
|
if (find_line_start(boundary.s, boundary.len, &end,
|
|
&len))
|
|
{
|
|
LM_DBG("found boundary %.*s\n", boundary.len, boundary.s);
|
|
bstart = end;
|
|
end = end + boundary.len;
|
|
len = len - boundary.len;
|
|
if (!(t = get_line(end, len))) {
|
|
LM_ERR("no CRLF found after boundary\n");
|
|
goto err;
|
|
}
|
|
end += t; len = end-start;
|
|
pkg_free(boundary.s);
|
|
boundary.s = NULL;
|
|
if(mode==1) {
|
|
end = body_headers_end;
|
|
val.rs.s = end;
|
|
val.rs.len = bstart - val.rs.s;
|
|
} else {
|
|
val.rs.s = start;
|
|
val.rs.len = len;
|
|
}
|
|
LM_DBG("output result: %.*s\n", val.rs.len, val.rs.s);
|
|
val.flags = PV_VAL_STR;
|
|
dst = (pv_spec_t *)ovar;
|
|
dst->setf(msg, &dst->pvp, (int)EQ_T, &val);
|
|
return 1;
|
|
}
|
|
LM_ERR("boundary not found after content\n");
|
|
goto err;
|
|
}
|
|
start = end;
|
|
} else {
|
|
LM_ERR("failed to match on content-type\n");
|
|
goto err;
|
|
}
|
|
}
|
|
err:
|
|
if(boundary.s) pkg_free(boundary.s);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int get_body_part_raw_f(sip_msg_t* msg, char* ctype, char* ovar)
|
|
{
|
|
return get_body_part_helper(msg, ctype, ovar, 0);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int get_body_part_f(sip_msg_t* msg, char* ctype, char* ovar)
|
|
{
|
|
return get_body_part_helper(msg, ctype, ovar, 1);
|
|
}
|
|
|
|
/*
|
|
* Fix get_body_part_raw params: content type (string that may contain pvars) and
|
|
* result (writable pvar).
|
|
*/
|
|
static int fixup_get_body_part(void** param, int param_no)
|
|
{
|
|
if (param_no == 1) {
|
|
return fixup_spve_null(param, 1);
|
|
}
|
|
|
|
if (param_no == 2) {
|
|
if (fixup_pvar_null(param, 1) != 0) {
|
|
LM_ERR("failed to fixup result pvar\n");
|
|
return -1;
|
|
}
|
|
if (((pv_spec_t *)(*param))->setf == NULL) {
|
|
LM_ERR("result pvar is not writeble\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LM_ERR("invalid parameter number <%d>\n", param_no);
|
|
return -1;
|
|
}
|
|
|
|
static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0)
|
|
{
|
|
str s0;
|
|
|
|
if(key==NULL)
|
|
{
|
|
LM_ERR("bad parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)key, &s0)!=0)
|
|
{
|
|
LM_ERR("cannot print the format\n");
|
|
return -1;
|
|
}
|
|
|
|
if ( add_lump_rpl( msg, s0.s, s0.len, LUMP_RPL_HDR)==0 )
|
|
{
|
|
LM_ERR("unable to add lump_rl\n");
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* add str1 to end of header or str1.r-uri.str2 */
|
|
|
|
int add_hf_helper(struct sip_msg* msg, str *str1, str *str2,
|
|
gparam_p hfval, int mode, gparam_p hfanc)
|
|
{
|
|
struct lump* anchor;
|
|
struct hdr_field *hf;
|
|
char *s;
|
|
int len;
|
|
str s0;
|
|
|
|
if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
|
|
LM_ERR("error while parsing message\n");
|
|
return -1;
|
|
}
|
|
|
|
hf = 0;
|
|
if(hfanc!=NULL) {
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
if(hfanc->type==GPARAM_TYPE_INT)
|
|
{
|
|
if (hfanc->v.i!=hf->type)
|
|
continue;
|
|
} else {
|
|
if (hf->name.len!=hfanc->v.str.len)
|
|
continue;
|
|
if (cmp_hdrname_str(&hf->name,&hfanc->v.str)!=0)
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(mode == 0) { /* append */
|
|
if(hf==0) { /* after last header */
|
|
anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
|
|
} else { /* after hf */
|
|
anchor = anchor_lump(msg, hf->name.s + hf->len - msg->buf, 0, 0);
|
|
}
|
|
} else { /* insert */
|
|
if(hf==0) { /* before first header */
|
|
anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0);
|
|
} else { /* before hf */
|
|
anchor = anchor_lump(msg, hf->name.s - msg->buf, 0, 0);
|
|
}
|
|
}
|
|
|
|
if(anchor == 0) {
|
|
LM_ERR("can't get anchor\n");
|
|
return -1;
|
|
}
|
|
|
|
if(str1) {
|
|
s0 = *str1;
|
|
} else {
|
|
if(hfval) {
|
|
if(fixup_get_svalue(msg, hfval, &s0)!=0)
|
|
{
|
|
LM_ERR("cannot print the format\n");
|
|
return -1;
|
|
}
|
|
} else {
|
|
s0.len = 0;
|
|
s0.s = 0;
|
|
}
|
|
}
|
|
|
|
len=s0.len;
|
|
if (str2) len+= str2->len + REQ_LINE(msg).uri.len;
|
|
|
|
if(len==0) {
|
|
LM_INFO("nothing to add\n");
|
|
return -1;
|
|
}
|
|
|
|
s = (char*)pkg_malloc(len);
|
|
if (!s) {
|
|
LM_ERR("no pkg memory left\n");
|
|
return -1;
|
|
}
|
|
|
|
if (likely(s0.len>0)){
|
|
memcpy(s, s0.s, s0.len);
|
|
}
|
|
|
|
if (str2) {
|
|
memcpy(s+s0.len, REQ_LINE(msg).uri.s, REQ_LINE(msg).uri.len);
|
|
memcpy(s+s0.len+REQ_LINE(msg).uri.len, str2->s, str2->len );
|
|
}
|
|
|
|
if (insert_new_lump_before(anchor, s, len, 0) == 0) {
|
|
LM_ERR("can't insert lump\n");
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int append_hf_1(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
return add_hf_helper(msg, 0, 0, (gparam_p)str1, 0, 0);
|
|
}
|
|
|
|
static int append_hf_2(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
return add_hf_helper(msg, 0, 0, (gparam_p)str1, 0,
|
|
(gparam_p)str2);
|
|
}
|
|
|
|
static int insert_hf_1(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
return add_hf_helper(msg, 0, 0, (gparam_p)str1, 1, 0);
|
|
}
|
|
|
|
static int insert_hf_2(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
return add_hf_helper(msg, 0, 0, (gparam_p)str1, 1,
|
|
(gparam_p)str2);
|
|
}
|
|
|
|
static int append_urihf(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
return add_hf_helper(msg, (str*)str1, (str*)str2, 0, 0, 0);
|
|
}
|
|
|
|
static int is_method_f(struct sip_msg *msg, char *meth, char *str2 )
|
|
{
|
|
str *m;
|
|
|
|
m = (str*)meth;
|
|
if(msg->first_line.type==SIP_REQUEST)
|
|
{
|
|
if(m->s==0)
|
|
return (msg->first_line.u.request.method_value&m->len)?1:-1;
|
|
else
|
|
return (msg->first_line.u.request.method_value==METHOD_OTHER
|
|
&& msg->first_line.u.request.method.len==m->len
|
|
&& (strncasecmp(msg->first_line.u.request.method.s, m->s,
|
|
m->len)==0))?1:-1;
|
|
}
|
|
if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL)
|
|
{
|
|
LM_ERR("cannot parse cseq header\n");
|
|
return -1; /* should it be 0 ?!?! */
|
|
}
|
|
if(m->s==0)
|
|
return (get_cseq(msg)->method_id&m->len)?1:-1;
|
|
else
|
|
return (get_cseq(msg)->method_id==METHOD_OTHER
|
|
&& get_cseq(msg)->method.len==m->len
|
|
&& (strncasecmp(get_cseq(msg)->method.s, m->s,
|
|
m->len)==0))?1:-1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert char* header_name to str* parameter
|
|
*/
|
|
static int hname_fixup(void** param, int param_no)
|
|
{
|
|
char c;
|
|
struct hdr_field hdr;
|
|
gparam_p gp = NULL;
|
|
|
|
gp = (gparam_p)pkg_malloc(sizeof(gparam_t));
|
|
if(gp == NULL)
|
|
{
|
|
LM_ERR("no more memory\n");
|
|
return E_UNSPEC;
|
|
}
|
|
memset(gp, 0, sizeof(gparam_t));
|
|
|
|
gp->v.str.s = (char*)*param;
|
|
gp->v.str.len = strlen(gp->v.str.s);
|
|
if(gp->v.str.len==0)
|
|
{
|
|
LM_ERR("empty header name parameter\n");
|
|
pkg_free(gp);
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
c = gp->v.str.s[gp->v.str.len];
|
|
gp->v.str.s[gp->v.str.len] = ':';
|
|
gp->v.str.len++;
|
|
|
|
if (parse_hname2_short(gp->v.str.s, gp->v.str.s + gp->v.str.len, &hdr)==0)
|
|
{
|
|
LM_ERR("error parsing header name\n");
|
|
pkg_free(gp);
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
gp->v.str.len--;
|
|
gp->v.str.s[gp->v.str.len] = c;
|
|
|
|
if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T)
|
|
{
|
|
LM_DBG("using hdr type (%d) instead of <%.*s>\n",
|
|
hdr.type, gp->v.str.len, gp->v.str.s);
|
|
pkg_free(gp->v.str.s);
|
|
gp->v.str.s = NULL;
|
|
gp->v.i = hdr.type;
|
|
gp->type = GPARAM_TYPE_INT;
|
|
} else {
|
|
gp->type = GPARAM_TYPE_STR;
|
|
LM_DBG("using hdr type name <%.*s>\n", gp->v.str.len, gp->v.str.s);
|
|
}
|
|
|
|
*param = (void*)gp;
|
|
return 0;
|
|
}
|
|
|
|
static int free_hname_fixup(void** param, int param_no)
|
|
{
|
|
if(*param)
|
|
{
|
|
if(((gparam_p)(*param))->type==GPARAM_TYPE_STR)
|
|
pkg_free(((gparam_p)(*param))->v.str.s);
|
|
pkg_free(*param);
|
|
*param = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Convert char* method to str* parameter
|
|
*/
|
|
static int fixup_method(void** param, int param_no)
|
|
{
|
|
str* s;
|
|
char *p;
|
|
int m;
|
|
unsigned int method;
|
|
|
|
s = (str*)pkg_malloc(sizeof(str));
|
|
if (!s) {
|
|
LM_ERR("no pkg memory left\n");
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
s->s = (char*)*param;
|
|
s->len = strlen(s->s);
|
|
if(s->len==0)
|
|
{
|
|
LM_ERR("empty method name\n");
|
|
pkg_free(s);
|
|
return E_UNSPEC;
|
|
}
|
|
m=0;
|
|
p=s->s;
|
|
while(*p)
|
|
{
|
|
if(*p=='|')
|
|
{
|
|
*p = ',';
|
|
m=1;
|
|
}
|
|
p++;
|
|
}
|
|
if(parse_methods(s, &method)!=0)
|
|
{
|
|
LM_ERR("bad method names\n");
|
|
pkg_free(s);
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
if(m==1)
|
|
{
|
|
if(method==METHOD_UNDEF || method&METHOD_OTHER)
|
|
{
|
|
LM_ERR("unknown method in list [%.*s/%d] - must be only defined methods\n",
|
|
s->len, s->s, method);
|
|
pkg_free(s);
|
|
return E_UNSPEC;
|
|
}
|
|
LM_DBG("using id for methods [%.*s/%d]\n",
|
|
s->len, s->s, method);
|
|
s->s = 0;
|
|
s->len = method;
|
|
} else {
|
|
if(method!=METHOD_UNDEF && method!=METHOD_OTHER)
|
|
{
|
|
LM_DBG("using id for method [%.*s/%d]\n",
|
|
s->len, s->s, method);
|
|
s->s = 0;
|
|
s->len = method;
|
|
} else
|
|
LM_DBG("name for method [%.*s/%d]\n",
|
|
s->len, s->s, method);
|
|
}
|
|
|
|
*param = (void*)s;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Convert char* privacy value to corresponding bit value
|
|
*/
|
|
int fixup_privacy(void** param, int param_no)
|
|
{
|
|
str p;
|
|
unsigned int val;
|
|
|
|
p.s = (char*)*param;
|
|
p.len = strlen(p.s);
|
|
|
|
if (p.len == 0) {
|
|
LM_ERR("empty privacy value\n");
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
if (parse_priv_value(p.s, p.len, &val) != p.len) {
|
|
LM_ERR("invalid privacy value\n");
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
*param = (void *)(long)val;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Fix in_list params: subject and list (strings that may contain pvars),
|
|
* separator (string)
|
|
*/
|
|
static int fixup_in_list(void** param, int param_no)
|
|
{
|
|
if ((param_no == 1) || (param_no == 2)) return fixup_spve_null(param, 1);
|
|
|
|
if (param_no == 3) {
|
|
if ((strlen((char *)*param) != 1) || (*((char *)(*param)) == 0)) {
|
|
LM_ERR("invalid separator parameter\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LM_ERR("invalid parameter number <%d>\n", param_no);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Free in_list params
|
|
*/
|
|
static int fixup_free_in_list(void** param, int param_no)
|
|
{
|
|
if ((param_no == 1) || (param_no == 2)) {
|
|
return fixup_free_spve_null(param, 1);
|
|
}
|
|
|
|
if (param_no == 3) return 0;
|
|
|
|
LM_ERR("invalid parameter number <%d>\n", param_no);
|
|
return -1;
|
|
}
|
|
|
|
static int add_header_fixup(void** param, int param_no)
|
|
{
|
|
if(param_no==1)
|
|
{
|
|
return fixup_spve_null(param, param_no);
|
|
} else if(param_no==2) {
|
|
return hname_fixup(param, param_no);
|
|
} else {
|
|
LM_ERR("wrong number of parameters\n");
|
|
return E_UNSPEC;
|
|
}
|
|
}
|
|
|
|
|
|
static int fixup_body_type(void** param, int param_no)
|
|
{
|
|
char *p;
|
|
char *r;
|
|
unsigned int type;
|
|
|
|
if(param_no==1) {
|
|
p = (char*)*param;
|
|
if (p==0 || p[0]==0) {
|
|
type = 0;
|
|
} else {
|
|
r = decode_mime_type( p, p+strlen(p) , &type);
|
|
if (r==0) {
|
|
LM_ERR("unsupported mime <%s>\n",p);
|
|
return E_CFG;
|
|
}
|
|
if ( r!=p+strlen(p) ) {
|
|
LM_ERR("multiple mimes not supported!\n");
|
|
return E_CFG;
|
|
}
|
|
}
|
|
pkg_free(*param);
|
|
*param = (void*)(long)type;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
static int has_body_f(struct sip_msg *msg, char *type, char *str2 )
|
|
{
|
|
int mime;
|
|
|
|
/* parse content len hdr */
|
|
if ( msg->content_length==NULL &&
|
|
(parse_headers(msg,HDR_CONTENTLENGTH_F, 0)==-1||msg->content_length==NULL))
|
|
return -1;
|
|
|
|
if (get_content_length (msg)==0) {
|
|
LM_DBG("content length is zero\n");
|
|
/* Nothing to see here, please move on. */
|
|
return -1;
|
|
}
|
|
|
|
/* check type also? */
|
|
if (type==0)
|
|
return 1;
|
|
|
|
/* the function search for and parses the Content-Type hdr */
|
|
mime = parse_content_type_hdr (msg);
|
|
if (mime<0) {
|
|
LM_ERR("failed to extract content type hdr\n");
|
|
return -1;
|
|
}
|
|
if (mime==0) {
|
|
/* content type hdr not found -> according the RFC3261 we
|
|
* assume APPLICATION/SDP --bogdan */
|
|
mime = ((TYPE_APPLICATION << 16) + SUBTYPE_SDP);
|
|
}
|
|
LM_DBG("content type is %d\n",mime);
|
|
|
|
if ( (unsigned int)mime!=(unsigned int)(unsigned long)type )
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int is_privacy_f(struct sip_msg *msg, char *_privacy, char *str2 )
|
|
{
|
|
if (parse_privacy(msg) == -1)
|
|
return -1;
|
|
|
|
return get_privacy_values(msg) & ((unsigned int)(long)_privacy) ? 1 : -1;
|
|
|
|
}
|
|
|
|
/*
|
|
* Checks if subject is found in list
|
|
*/
|
|
int in_list_f(struct sip_msg* _m, char* _subject, char* _list, char* _sep)
|
|
{
|
|
str subject, list;
|
|
int sep;
|
|
char *at, *past, *next_sep, *s;
|
|
|
|
if (fixup_get_svalue(_m, (gparam_p)_subject, &subject) != 0) {
|
|
LM_ERR("cannot get subject value\n");
|
|
return -1;
|
|
} else {
|
|
if (subject.len == 0) {
|
|
LM_ERR("subject cannot be empty string\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (fixup_get_svalue(_m, (gparam_p)_list, &list) != 0) {
|
|
LM_ERR("cannot get list value\n");
|
|
return -1;
|
|
} else {
|
|
if (list.len == 0) return -1;
|
|
}
|
|
|
|
sep = _sep[0];
|
|
|
|
at = list.s;
|
|
past = list.s + list.len;
|
|
|
|
/* Eat leading white space */
|
|
while ((at < past) &&
|
|
((*at == ' ') || (*at == '\t') || (*at == '\r') || (*at == '\n') )) {
|
|
at++;
|
|
}
|
|
|
|
while (at < past) {
|
|
next_sep = index(at, sep);
|
|
s = next_sep;
|
|
|
|
if (s == NULL) {
|
|
/* Eat trailing white space */
|
|
while ((at < past) &&
|
|
((*(past-1) == ' ') || (*(past-1) == '\t') || (*(past-1) == '\r') || (*(past-1) == '\n') )) {
|
|
past--;
|
|
}
|
|
if ((subject.len == (past - at)) &&
|
|
strncmp(at, subject.s, subject.len) == 0) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
/* Eat trailing white space */
|
|
while ((at < s) &&
|
|
((*(s-1) == ' ') || (*(s-1) == '\t') || (*(s-1) == '\r') || (*(s-1) == '\n') )) {
|
|
s--;
|
|
}
|
|
if ((subject.len == (s - at)) &&
|
|
strncmp(at, subject.s, subject.len) == 0) {
|
|
return 1;
|
|
} else {
|
|
at = next_sep + 1;
|
|
/* Eat leading white space */
|
|
while ((at < past) &&
|
|
((*at == ' ') || (*at == '\t') || (*at == '\r') || (*at == '\n') )) {
|
|
at++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int cmp_str_f(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
str s1;
|
|
str s2;
|
|
int ret;
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)str1, &s1)!=0)
|
|
{
|
|
LM_ERR("cannot get first parameter\n");
|
|
return -8;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)str2, &s2)!=0)
|
|
{
|
|
LM_ERR("cannot get second parameter\n");
|
|
return -8;
|
|
}
|
|
ret = cmp_str(&s1, &s2);
|
|
if(ret==0)
|
|
return 1;
|
|
if(ret>0)
|
|
return -1;
|
|
return -2;
|
|
}
|
|
|
|
static int cmp_istr_f(struct sip_msg *msg, char *str1, char *str2)
|
|
{
|
|
str s1;
|
|
str s2;
|
|
int ret;
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)str1, &s1)!=0)
|
|
{
|
|
LM_ERR("cannot get first parameter\n");
|
|
return -8;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)str2, &s2)!=0)
|
|
{
|
|
LM_ERR("cannot get second parameter\n");
|
|
return -8;
|
|
}
|
|
ret = cmpi_str(&s1, &s2);
|
|
if(ret==0)
|
|
return 1;
|
|
if(ret>0)
|
|
return -1;
|
|
return -2;
|
|
}
|
|
|
|
static int starts_with_f(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
str s1;
|
|
str s2;
|
|
int ret;
|
|
|
|
if(fixup_get_svalue(msg, (gparam_p)str1, &s1)!=0)
|
|
{
|
|
LM_ERR("cannot get first parameter\n");
|
|
return -8;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)str2, &s2)!=0)
|
|
{
|
|
LM_ERR("cannot get second parameter\n");
|
|
return -8;
|
|
}
|
|
if (s1.len < s2.len) return -1;
|
|
ret = strncmp(s1.s, s2.s, s2.len);
|
|
if(ret==0)
|
|
return 1;
|
|
if(ret>0)
|
|
return -1;
|
|
return -2;
|
|
}
|
|
|
|
static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 )
|
|
{
|
|
int sdp_session_num = 0, sdp_stream_num;
|
|
sdp_session_cell_t* sdp_session;
|
|
sdp_stream_cell_t* sdp_stream;
|
|
|
|
if (0 == parse_sdp(msg)) {
|
|
for(;;) {
|
|
sdp_session = get_sdp_session(msg, sdp_session_num);
|
|
if(!sdp_session) break;
|
|
sdp_stream_num = 0;
|
|
for(;;) {
|
|
sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
|
|
if(!sdp_stream) break;
|
|
if(sdp_stream->media.len==AUDIO_STR_LEN &&
|
|
strncmp(sdp_stream->media.s,AUDIO_STR,AUDIO_STR_LEN)==0 &&
|
|
sdp_stream->is_on_hold)
|
|
return 1;
|
|
sdp_stream_num++;
|
|
}
|
|
sdp_session_num++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int fixup_regexpNL_none(void** param, int param_no)
|
|
{
|
|
regex_t* re;
|
|
|
|
if (param_no != 1 && param_no != 2 )
|
|
{
|
|
LM_ERR("invalid parameter number %d\n", param_no);
|
|
return E_UNSPEC;
|
|
}
|
|
if (param_no == 2)
|
|
return 0;
|
|
/* param 1 */
|
|
if ((re=pkg_malloc(sizeof(regex_t)))==0) {
|
|
LM_ERR("no more pkg memory\n");
|
|
return E_OUT_OF_MEM;
|
|
}
|
|
if (regcomp(re, *param, REG_EXTENDED|REG_ICASE)) {
|
|
pkg_free(re);
|
|
LM_ERR("bad re %s\n", (char*)*param);
|
|
return E_BAD_RE;
|
|
}
|
|
/* free string */
|
|
pkg_free(*param);
|
|
/* replace it with the compiled re */
|
|
*param=re;
|
|
return 0;
|
|
}
|
|
|
|
/*! \brief
|
|
* fixup for functions that get two parameters
|
|
* - first parameter is converted to regular expression structure
|
|
* - second parameter is not converted
|
|
*/
|
|
int fixup_regexp_none(void** param, int param_no)
|
|
{
|
|
if (param_no != 1 && param_no != 2 )
|
|
{
|
|
LM_ERR("invalid parameter number %d\n", param_no);
|
|
return E_UNSPEC;
|
|
}
|
|
if (param_no == 1)
|
|
return fixup_regexp_null(param, 1);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* fixup free for functions that get two parameters
|
|
* - first parameter was converted to regular expression
|
|
* - second parameter was notconverted
|
|
*/
|
|
int fixup_free_regexp_none(void** param, int param_no)
|
|
{
|
|
if (param_no != 1 && param_no != 2 )
|
|
{
|
|
LM_ERR("invalid parameter number %d\n", param_no);
|
|
return E_UNSPEC;
|
|
}
|
|
if (param_no == 1)
|
|
return fixup_free_regexp_null(param, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int search_hf_f(struct sip_msg* msg, char* str_hf, char* re, char *flags)
|
|
{
|
|
hdr_field_t *hf;
|
|
hdr_field_t *hfl = NULL;
|
|
str body;
|
|
gparam_t *gp;
|
|
regmatch_t pmatch;
|
|
char c;
|
|
int ret;
|
|
|
|
gp = (gparam_t*)str_hf;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
if(gp->type==GPARAM_TYPE_INT)
|
|
{
|
|
if (gp->v.i!=hf->type)
|
|
continue;
|
|
} else {
|
|
if (hf->name.len!=gp->v.str.len)
|
|
continue;
|
|
if (cmp_hdrname_str(&hf->name,&gp->v.str)!=0)
|
|
continue;
|
|
}
|
|
|
|
if(flags==NULL || *flags!='l')
|
|
{
|
|
body = hf->body;
|
|
c = body.s[body.len];
|
|
body.s[body.len] = '\0';
|
|
ret = regexec((regex_t*) re, body.s, 1, &pmatch, 0);
|
|
body.s[body.len] = c;
|
|
if(ret==0)
|
|
{
|
|
/* match */
|
|
if(flags==NULL || *flags!='l')
|
|
return 1;
|
|
} else {
|
|
if(flags!=NULL && *flags=='f')
|
|
return -1;
|
|
}
|
|
} else {
|
|
hfl = hf;
|
|
}
|
|
}
|
|
if(hfl!=NULL)
|
|
{
|
|
hf = hfl;
|
|
body = hf->body;
|
|
c = body.s[body.len];
|
|
body.s[body.len] = '\0';
|
|
ret = regexec((regex_t*) re, body.s, 1, &pmatch, 0);
|
|
body.s[body.len] = c;
|
|
if(ret==0)
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Convert header name, regexp and flags
|
|
*/
|
|
static int fixup_search_hf(void** param, int param_no)
|
|
{
|
|
if(param_no==1)
|
|
return hname_fixup(param, param_no);
|
|
if(param_no==2)
|
|
return fixup_regexp_null(param, 1);
|
|
return 0;
|
|
}
|
|
|
|
/* sed-perl style re: s/regular expression/replacement/flags */
|
|
static int subst_hf_f(struct sip_msg *msg, char *str_hf, char *subst, char *flags)
|
|
{
|
|
struct lump* l;
|
|
struct replace_lst* lst = NULL;
|
|
struct replace_lst* rpl = NULL;
|
|
char* begin;
|
|
struct subst_expr* se;
|
|
int off;
|
|
int nmatches=0;
|
|
str body;
|
|
hdr_field_t *hf;
|
|
hdr_field_t *hfl = NULL;
|
|
gparam_t *gp;
|
|
char c;
|
|
int ret;
|
|
|
|
ret = -1;
|
|
gp = (gparam_t*)str_hf;
|
|
se=(struct subst_expr*)subst;
|
|
|
|
/* we need to be sure we have seen all HFs */
|
|
if(parse_headers(msg, HDR_EOH_F, 0)<0) {
|
|
LM_ERR("error while parsing message headers\n");
|
|
return -1;
|
|
}
|
|
for (hf=msg->headers; hf; hf=hf->next) {
|
|
if(gp->type==GPARAM_TYPE_INT)
|
|
{
|
|
if (gp->v.i!=hf->type)
|
|
continue;
|
|
} else {
|
|
if (hf->name.len!=gp->v.str.len)
|
|
continue;
|
|
if (cmp_hdrname_str(&hf->name,&gp->v.str)!=0)
|
|
continue;
|
|
}
|
|
|
|
if(flags==NULL || *flags!='l')
|
|
{
|
|
body = hf->body;
|
|
c = body.s[body.len];
|
|
body.s[body.len] = '\0';
|
|
|
|
begin=body.s;
|
|
|
|
off=begin-msg->buf;
|
|
if (lst) replace_lst_free(lst);
|
|
lst=subst_run(se, begin, msg, &nmatches);
|
|
body.s[body.len] = c;
|
|
if(lst==0 && flags!=NULL && *flags=='f')
|
|
goto error; /* not found */
|
|
if(lst!=0)
|
|
ret=1;
|
|
for (rpl=lst; rpl; rpl=rpl->next)
|
|
{
|
|
LM_DBG("%s replacing at offset %d [%.*s] with [%.*s]\n",
|
|
exports.name, rpl->offset+off,
|
|
rpl->size, rpl->offset+off+msg->buf,
|
|
rpl->rpl.len, rpl->rpl.s);
|
|
if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
|
|
{
|
|
ret=-1;
|
|
goto error;
|
|
}
|
|
/* hack to avoid re-copying rpl, possible because both
|
|
* replace_lst & lumps use pkg_malloc */
|
|
if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0)
|
|
{
|
|
LM_ERR("%s could not insert new lump\n",
|
|
exports.name);
|
|
ret=-1;
|
|
goto error;
|
|
}
|
|
/* hack continued: set rpl.s to 0 so that replace_lst_free will
|
|
* not free it */
|
|
rpl->rpl.s=0;
|
|
rpl->rpl.len=0;
|
|
}
|
|
} else {
|
|
hfl = hf;
|
|
}
|
|
/* if flags set for first header, then all done */
|
|
if(flags!=NULL && *flags=='f')
|
|
goto done;
|
|
}
|
|
if(hfl!=NULL)
|
|
{
|
|
hf= hfl;
|
|
body = hf->body;
|
|
c = body.s[body.len];
|
|
body.s[body.len] = '\0';
|
|
|
|
begin=body.s;
|
|
|
|
off=begin-msg->buf;
|
|
if (lst) replace_lst_free(lst);
|
|
lst=subst_run(se, begin, msg, &nmatches);
|
|
body.s[body.len] = c;
|
|
if(lst==0)
|
|
goto error; /* not found */
|
|
ret=1;
|
|
for (rpl=lst; rpl; rpl=rpl->next)
|
|
{
|
|
LM_DBG("%s replacing at offset %d [%.*s] with [%.*s]\n",
|
|
exports.name, rpl->offset+off,
|
|
rpl->size, rpl->offset+off+msg->buf,
|
|
rpl->rpl.len, rpl->rpl.s);
|
|
if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
|
|
{
|
|
ret=-1;
|
|
goto error;
|
|
}
|
|
/* hack to avoid re-copying rpl, possible because both
|
|
* replace_lst & lumps use pkg_malloc */
|
|
if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0)
|
|
{
|
|
LM_ERR("%s could not insert new lump\n",
|
|
exports.name);
|
|
ret=-1;
|
|
goto error;
|
|
}
|
|
/* hack continued: set rpl.s to 0 so that replace_lst_free will
|
|
* not free it */
|
|
rpl->rpl.s=0;
|
|
rpl->rpl.len=0;
|
|
}
|
|
}
|
|
error:
|
|
if (nmatches<0)
|
|
LM_ERR("%s subst_run failed\n", exports.name);
|
|
LM_DBG("lst was %p\n", lst);
|
|
done:
|
|
if (lst) replace_lst_free(lst);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Convert header name, substexp and flags
|
|
*/
|
|
static int fixup_subst_hf(void** param, int param_no)
|
|
{
|
|
if(param_no==1)
|
|
return hname_fixup(param, param_no);
|
|
if(param_no==2)
|
|
return fixup_substre(param, 1);
|
|
return 0;
|
|
}
|
|
|