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.
kamailio/modules/textopsx/textopsx.c

431 lines
9.6 KiB

/**
*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of ser, a free SIP server.
*
* ser 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fnmatch.h>
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../data_lump.h"
#include "../../msg_translator.h"
#include "../../tcp_options.h"
#include "../../mod_fix.h"
#include "api.h"
MODULE_VERSION
static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2);
static int change_reply_status_f(sip_msg_t*, char*, char*);
static int change_reply_status_fixup(void** param, int param_no);
static int w_keep_hf_f(sip_msg_t*, char*, char*);
static int w_fnmatch2_f(sip_msg_t*, char*, char*);
static int w_fnmatch3_f(sip_msg_t*, char*, char*, char*);
static int fixup_fnmatch(void** param, int param_no);
static int w_remove_body_f(struct sip_msg*, char*, char *);
static int bind_textopsx(textopsx_api_t *tob);
static int mod_init(void);
/* cfg functions */
static cmd_export_t cmds[] = {
{"msg_apply_changes", (cmd_function)msg_apply_changes_f, 0,
0, REQUEST_ROUTE },
{"change_reply_status", change_reply_status_f, 2,
change_reply_status_fixup, ONREPLY_ROUTE },
{"remove_body", (cmd_function)w_remove_body_f, 0,
0, ANY_ROUTE },
{"keep_hf", (cmd_function)w_keep_hf_f, 1,
fixup_regexp_null, ANY_ROUTE },
{"fnmatch", (cmd_function)w_fnmatch2_f, 2,
fixup_fnmatch, ANY_ROUTE },
{"fnmatch", (cmd_function)w_fnmatch3_f, 3,
fixup_fnmatch, ANY_ROUTE },
{"bind_textopsx", (cmd_function)bind_textopsx, 1,
0, ANY_ROUTE },
{0,0,0,0,0}
};
/* module exports structure */
struct module_exports exports= {
"textopsx",
cmds, /* cfg functions */
0, /* RPC methods */
0, /* cfg parameters */
mod_init, /* initialization function */
0, /* response function */
0, /* destroy function */
0, /* on_cancel function */
0 /* per-child init function */
};
/**
* init module function
*/
static int mod_init(void)
{
#ifdef USE_TCP
tcp_set_clone_rcvbuf(1);
#endif
return 0;
}
/**
*
*/
static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
{
struct dest_info dst;
str obuf;
sip_msg_t tmp;
if(get_route_type()!=REQUEST_ROUTE)
{
LM_ERR("invalid usage - not in request route\n");
return -1;
}
init_dest_info(&dst);
dst.proto = PROTO_UDP;
obuf.s = build_req_buf_from_sip_req(msg,
(unsigned int*)&obuf.len, &dst,
BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
if(obuf.s == NULL)
{
LM_ERR("couldn't update msg buffer content\n");
return -1;
}
if(obuf.len>=BUF_SIZE)
{
LM_ERR("new buffer overflow (%d)\n", obuf.len);
pkg_free(obuf.s);
return -1;
}
/* temporary copy */
memcpy(&tmp, msg, sizeof(sip_msg_t));
/* reset dst uri and path vector to avoid freeing - restored later */
if(msg->dst_uri.s!=NULL)
{
msg->dst_uri.s = NULL;
msg->dst_uri.len = 0;
}
if(msg->path_vec.s!=NULL)
{
msg->path_vec.s = NULL;
msg->path_vec.len = 0;
}
/* free old msg structure */
free_sip_msg(msg);
memset(msg, 0, sizeof(sip_msg_t));
/* restore msg fields */
msg->buf = tmp.buf;
msg->id = tmp.id;
msg->rcv = tmp.rcv;
msg->set_global_address = tmp.set_global_address;
msg->set_global_port = tmp.set_global_port;
msg->flags = tmp.flags;
msg->msg_flags = tmp.msg_flags;
msg->hash_index = tmp.hash_index;
msg->force_send_socket = tmp.force_send_socket;
msg->fwd_send_flags = tmp.fwd_send_flags;
msg->rpl_send_flags = tmp.rpl_send_flags;
msg->dst_uri = tmp.dst_uri;
msg->path_vec = tmp.path_vec;
memcpy(msg->buf, obuf.s, obuf.len);
msg->len = obuf.len;
msg->buf[msg->len] = '\0';
/* free new buffer - copied in the static buffer from old sip_msg_t */
pkg_free(obuf.s);
/* reparse the message */
LM_DBG("SIP Request content updated - reparsing\n");
if (parse_msg(msg->buf, msg->len, msg)!=0){
LM_ERR("parse_msg failed\n");
return -1;
}
return 1;
}
/**
*
*/
static int change_reply_status_fixup(void** param, int param_no)
{
if (param_no == 1) {
return fixup_var_int_12(param, param_no);
} else if (param_no == 2)
return fixup_var_pve_str_12(param, param_no);
else
return 0;
}
/**
*
*/
static int change_reply_status_f(struct sip_msg* msg, char* _code, char* _reason)
{
int code;
str reason;
struct lump *l;
char *ch;
if (get_int_fparam(&code, msg, (fparam_t*)_code)
|| get_str_fparam(&reason, msg, (fparam_t*)_reason)
|| (reason.len == 0)
) {
LOG(L_ERR, "ERROR: textops: cannot get parameter\n");
return -1;
}
if ((code < 100) || (code > 699)) {
LOG(L_ERR, "ERROR: textops: wrong status code: %d\n",
code);
return -1;
}
if (((code < 300) || (msg->REPLY_STATUS < 300))
&& (code/100 != msg->REPLY_STATUS/100)
) {
LOG(L_ERR, "ERROR: textops: the class of provisional or "
"positive final replies cannot be changed\n");
return -1;
}
/* rewrite the status code directly in the message buffer */
msg->first_line.u.reply.statuscode = code;
msg->first_line.u.reply.status.s[2] = code % 10 + '0'; code /= 10;
msg->first_line.u.reply.status.s[1] = code % 10 + '0'; code /= 10;
msg->first_line.u.reply.status.s[0] = code + '0';
l = del_lump(msg,
msg->first_line.u.reply.reason.s - msg->buf,
msg->first_line.u.reply.reason.len,
0);
if (!l) {
LOG(L_ERR, "ERROR: textops(): Failed to add del lump\n");
return -1;
}
/* clone the reason phrase, the lumps need to be pkg allocated */
ch = (char *)pkg_malloc(reason.len);
if (!ch) {
LOG(L_ERR, "ERROR: textops: Not enough memory\n");
return -1;
}
memcpy(ch, reason.s, reason.len);
if (insert_new_lump_after(l, ch, reason.len, 0)==0){
LOG(L_ERR, "ERROR: textops: failed to add new lump: %.*s\n",
reason.len, ch);
pkg_free(ch);
return -1;
}
return 1;
}
/**
*
*/
static int w_remove_body_f(struct sip_msg *msg, char *p1, char *p2)
{
str body = {0,0};
body.len = 0;
body.s = get_body(msg);
if (body.s==0)
{
LM_DBG("no body in the message\n");
return 1;
}
body.len = msg->buf + msg->len - body.s;
if (body.len<=0)
{
LM_DBG("empty body in the message\n");
return 1;
}
if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0)
{
LM_ERR("cannot remove body\n");
return -1;
}
return 1;
}
/**
*
*/
static int w_keep_hf_f(struct sip_msg* msg, char* key, char* foo)
{
struct hdr_field *hf;
regex_t *re;
regmatch_t pmatch;
char c;
struct lump* l;
re = (regex_t*)key;
/* we need to be sure we have seen all HFs */
parse_headers(msg, HDR_EOH_F, 0);
for (hf=msg->headers; hf; hf=hf->next)
{
switch(hf->type) {
case HDR_FROM_T:
case HDR_TO_T:
case HDR_CALLID_T:
case HDR_CSEQ_T:
case HDR_VIA_T:
case HDR_VIA2_T:
case HDR_CONTACT_T:
case HDR_CONTENTLENGTH_T:
case HDR_CONTENTTYPE_T:
case HDR_ROUTE_T:
case HDR_RECORDROUTE_T:
case HDR_MAXFORWARDS_T:
continue;
default:
;
}
c = hf->name.s[hf->name.len];
hf->name.s[hf->name.len] = '\0';
if (regexec(re, hf->name.s, 1, &pmatch, 0)!=0)
{
/* no match => remove */
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;
}
} else {
hf->name.s[hf->name.len] = c;
}
}
return -1;
}
/**
*
*/
static int w_fnmatch(str *val, str *match, str *flags)
{
int i;
i = 0;
#ifdef FNM_CASEFOLD
if(flags && (flags->s[0]=='i' || flags->s[0]=='I'))
i = FNM_CASEFOLD;
#endif
if(fnmatch(match->s, val->s, i)==0)
return 0;
return -1;
}
/**
*
*/
static int w_fnmatch2_f(sip_msg_t *msg, char *val, char *match)
{
str sval;
str smatch;
if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
|| get_str_fparam(&smatch, msg, (fparam_t*)match)<0)
{
LM_ERR("invalid parameters");
return -1;
}
if(w_fnmatch(&sval, &smatch, NULL)<0)
return -1;
return 1;
}
/**
*
*/
static int w_fnmatch3_f(sip_msg_t *msg, char *val, char *match, char *flags)
{
str sval;
str smatch;
str sflags;
if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
|| get_str_fparam(&smatch, msg, (fparam_t*)match)<0
|| get_str_fparam(&sflags, msg, (fparam_t*)flags)<0)
{
LM_ERR("invalid parameters");
return -1;
}
if(w_fnmatch(&sval, &smatch, &sflags)<0)
return -1;
return 1;
}
/**
*
*/
static int fixup_fnmatch(void** param, int param_no)
{
if (param_no == 1) {
return fixup_var_pve_12(param, param_no);
} else if (param_no == 2) {
return fixup_var_pve_12(param, param_no);
} else if (param_no == 3) {
return fixup_var_pve_12(param, param_no);
} else {
return 0;
}
}
/*
* Function to load the textops api.
*/
static int bind_textopsx(textopsx_api_t *tob){
if(tob==NULL){
LM_WARN("textopsx_binds: Cannot load textopsx API into a NULL pointer\n");
return -1;
}
tob->msg_apply_changes = msg_apply_changes_f;
return 0;
}