src/modules/acc/acc_logic.c
8ec042ca
 /*
  * Accounting module logic
  *
  * Copyright (C) 2001-2003 FhG Fokus
  * Copyright (C) 2006 Voice Sistem SRL
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
8ec042ca
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
8ec042ca
  * 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
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
8ec042ca
  * 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
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
8ec042ca
  *
  */
 
4e22b1ec
 /*! \file
  * \ingroup acc
  * \brief Acc:: Logic
  *
  * - Module: \ref acc
  */
 
8ec042ca
 #include <stdio.h>
 #include <string.h>
 
cf83221d
 #include "../../core/dprint.h"
 #include "../../core/sr_module.h"
 #include "../../core/parser/parse_from.h"
 #include "../../core/parser/parse_content.h"
 #include "../../core/strutils.h"
c4c671df
 #include "../../core/sip_msg_clone.h"
eb38b3df
 #include "../../modules/tm/tm_load.h"
8ec042ca
 #include "../rr/api.h"
cf83221d
 #include "../../core/flags.h"
42bdac92
 #include "../../core/mod_fix.h"
3efdeefd
 #include "../../core/kemi.h"
8ec042ca
 #include "acc.h"
56fa1561
 #include "acc_api.h"
8ec042ca
 #include "acc_mod.h"
 #include "acc_logic.h"
 
 extern struct tm_binds tmb;
 extern struct rr_binds rrb;
 
 struct acc_enviroment acc_env;
 
 
9aa1c821
 #define is_acc_flag_set(_rq,_flag)  (((_flag) != -1) && (isflagset((_rq), (_flag)) == 1))
8ec042ca
 
 #define is_failed_acc_on(_rq)  is_acc_flag_set(_rq,failed_transaction_flag)
 
 #define is_log_acc_on(_rq)     is_acc_flag_set(_rq,log_flag)
 #define is_log_mc_on(_rq)      is_acc_flag_set(_rq,log_missed_flag)
 
8eb6e6a0
 #define is_db_acc_on(_rq)     is_acc_flag_set(_rq,db_flag)
 #define is_db_mc_on(_rq)      is_acc_flag_set(_rq,db_missed_flag)
8ec042ca
 
 #define is_acc_on(_rq) \
ccf71c68
 	( (is_log_acc_on(_rq)) || (is_db_acc_on(_rq)) || (is_eng_acc_on(_rq)) )
8ec042ca
 
 #define is_mc_on(_rq) \
ccf71c68
 	( (is_log_mc_on(_rq)) || (is_db_mc_on(_rq)) || (is_eng_mc_on(_rq)) )
8ec042ca
 
 #define skip_cancel(_rq) \
 	(((_rq)->REQ_METHOD==METHOD_CANCEL) && report_cancels==0)
 
cf7a3249
 #define is_acc_prepare_on(_rq) \
16c2fcb3
 	(acc_prepare_always || is_acc_flag_set(_rq,acc_prepare_flag))
8ec042ca
 
 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps );
 
 
051300e0
 static inline struct hdr_field* get_rpl_to( struct cell *t, struct sip_msg *reply)
8ec042ca
 {
 	if (reply==FAKED_REPLY || !reply || !reply->to)
 		return t->uas.request->to;
 	else
 		return reply->to;
 }
 
051300e0
 void env_set_totag(struct cell *t, struct sip_msg *reply)
 {
 	if (reply==FAKED_REPLY || !reply || !reply->to)
 		tmb.t_get_reply_totag(t->uas.request, &acc_env.to_tag);
 }
8ec042ca
 
e74cb237
 int env_set_reason(struct sip_msg *reply, str *buff, int code) {
 
c5f6ff37
 	if (reply!=FAKED_REPLY || !buff || !buff->s || buff->len < 20)
 		return 0;
 	if (strncmp(buff->s, "SIP/2.0 ", 8) != 0) {
 		LM_ERR("not a SIP reply\n");
 		return 0;
 	}
e74cb237
 
 	/* Set the reason to a pointer in heap memory. It will contain the last seen FAKED_REPLY */
 	acc_env.reason.s = error_text(code);
 	acc_env.reason.len = strlen(acc_env.reason.s);
 	LM_DBG("reason[%.*s]\n", acc_env.reason.len, acc_env.reason.s);
 
c5f6ff37
 	return 0;
 }
 
8ec042ca
 static inline void env_set_to(struct hdr_field *to)
 {
 	acc_env.to = to;
 }
 
 static inline void env_set_text(char *p, int len)
 {
 	acc_env.text.s = p;
 	acc_env.text.len = len;
 }
 
 
 static inline void env_set_code_status( int code, struct sip_msg *reply)
 {
 	static char code_buf[INT2STR_MAX_LEN];
7f136429
 	str reason = {"Reason", 6};
 	struct hdr_field *hf;
8ec042ca
 
 	acc_env.code = code;
 	if (reply==FAKED_REPLY || reply==NULL) {
 		/* code */
 		acc_env.code_s.s =
 			int2bstr((unsigned long)code, code_buf, &acc_env.code_s.len);
 		/* reason */
e74cb237
 		/* In case of an ACK the reply == NULL, but the reason must be set when report_ack is 1 */
 		if (acc_env.reason.len == 0 || reply==NULL) { /* already extracted in case of locally generated replies */
c5f6ff37
 			acc_env.reason.s = error_text(code);
 			acc_env.reason.len = strlen(acc_env.reason.s);
 		}
8ec042ca
 	} else {
 		acc_env.code_s = reply->first_line.u.reply.status;
7f136429
 		hf = NULL;
42bdac92
 		if (reason_from_hf) {
7f136429
 			/* TODO: take reason from all Reason headers */
 			if(parse_headers(reply, HDR_EOH_F, 0) < 0) {
 				LM_ERR("error parsing headers\n");
 			} else {
 				for (hf=reply->headers; hf; hf=hf->next) {
 					if (cmp_hdrname_str(&hf->name, &reason)==0)
 						break;
 				}
 			}
 		}
 		if (hf == NULL) {
 			acc_env.reason = reply->first_line.u.reply.reason;
 		} else {
 			acc_env.reason = hf->body;
 		}
8ec042ca
 	}
 }
 
 
 static inline void env_set_comment(struct acc_param *accp)
 {
 	acc_env.code = accp->code;
 	acc_env.code_s = accp->code_s;
 	acc_env.reason = accp->reason;
 }
 
 
 static inline int acc_preparse_req(struct sip_msg *req)
 {
 	if ( (parse_headers(req,HDR_CALLID_F|HDR_CSEQ_F|HDR_FROM_F|HDR_TO_F,0)<0)
 	|| (parse_from_header(req)<0 ) ) {
789504a6
 		LM_ERR("failed to preparse request\n");
8ec042ca
 		return -1;
 	}
 	return 0;
 }
 
81c6e0bc
 int acc_parse_code(char *p, struct acc_param *param)
 {
 	if (p==NULL||param==NULL)
 		return -1;
8ec042ca
 
81c6e0bc
 	/* any code? */
 	if (param->reason.len>=3 && isdigit((int)p[0])
 	&& isdigit((int)p[1]) && isdigit((int)p[2]) ) {
 		param->code = (p[0]-'0')*100 + (p[1]-'0')*10 + (p[2]-'0');
 		param->code_s.s = p;
 		param->code_s.len = 3;
 		param->reason.s += 3;
 		for( ; isspace((int)param->reason.s[0]) ; param->reason.s++ );
 		param->reason.len = strlen(param->reason.s);
 	}
 	return 0;
 }
 
 int acc_get_param_value(struct sip_msg *rq, struct acc_param *param)
 {
 	if(param->elem!=NULL) {
69ccdc25
 		if(pv_printf_s(rq, param->elem, &param->reason)<0) {
81c6e0bc
 			LM_ERR("Can't get value for %.*s\n", param->reason.len, param->reason.s);
 			return -1;
 		}
 		if(acc_parse_code(param->reason.s, param)<0)
 		{
 			LM_ERR("Can't parse code\n");
 			return -1;
 		}
 	}
 	return 0;
 }
8ec042ca
 
 int w_acc_log_request(struct sip_msg *rq, char *comment, char *foo)
 {
81c6e0bc
 	struct acc_param *param = (struct acc_param*)comment;
8ec042ca
 	if (acc_preparse_req(rq)<0)
 		return -1;
81c6e0bc
 	if(acc_get_param_value(rq, param)<0)
 		return -1;
8ec042ca
 	env_set_to( rq->to );
81c6e0bc
 	env_set_comment(param);
8ec042ca
 	env_set_text( ACC_REQUEST, ACC_REQUEST_LEN);
 	return acc_log_request(rq);
 }
 
3efdeefd
 static int acc_param_parse(str *s, acc_param_t *accp)
 {
 	if(s==NULL || s->s==NULL || s->len<=0 || accp==NULL) {
 		LM_ERR("invalid parameters\n");
 		return -1;
 	}
 	memset(accp, 0, sizeof(acc_param_t));
 	accp->reason.s = s->s;
 	accp->reason.len = s->len;
 	if (strchr(s->s, PV_MARKER)!=NULL) {
 		/* there is a cfg variable - not through kemi */
 		LM_ERR("cfg variable detected - not supported\n");
 		return -1;
 	} else {
 		if(acc_parse_code(s->s, accp)<0) {
 			LM_ERR("failed to parse: [%.*s] (expected [code text])\n",
 					s->len, s->s);
 			return -1;
 		}
 	}
 	return 0;
 }
 
 int ki_acc_log_request(sip_msg_t *rq, str *comment)
 {
 	acc_param_t accp;
 
 	if(acc_param_parse(comment, &accp)<0) {
 		LM_ERR("failed execution\n");
 		return -1;
 	}
 	if (acc_preparse_req(rq)<0)
 		return -1;
 
 	env_set_to(rq->to);
 	env_set_comment(&accp);
 	env_set_text(ACC_REQUEST, ACC_REQUEST_LEN);
 	return acc_log_request(rq);
 }
8ec042ca
 
42bdac92
 
95ee0a3e
 int acc_db_set_table_name(struct sip_msg *msg, void *param, str *table)
 {
 #define DB_TABLE_NAME_SIZE	64
 	static char db_table_name_buf[DB_TABLE_NAME_SIZE];
 	str dbtable;
 
 	if(param!=NULL) {
 		if(get_str_fparam(&dbtable, msg, (fparam_t*)param)<0) {
 			LM_ERR("cannot get acc db table name\n");
 			return -1;
 		}
 		if(dbtable.len>=DB_TABLE_NAME_SIZE) {
 			LM_ERR("acc db table name too big [%.*s] max %d\n",
 					dbtable.len, dbtable.s, DB_TABLE_NAME_SIZE);
 			return -1;
 		}
 		strncpy(db_table_name_buf, dbtable.s, dbtable.len);
9a0147b8
 		db_table_name_buf[dbtable.len] = '\0';
95ee0a3e
 		env_set_text(db_table_name_buf, dbtable.len);
 	} else {
 		if(table==NULL) {
 			LM_ERR("no acc table name\n");
 			return -1;
 		}
 		env_set_text(table->s, table->len);
 	}
 	return 0;
 }
 
 
8ec042ca
 int w_acc_db_request(struct sip_msg *rq, char *comment, char *table)
 {
81c6e0bc
 	struct acc_param *param = (struct acc_param*)comment;
8ec042ca
 	if (!table) {
789504a6
 		LM_ERR("db support not configured\n");
8ec042ca
 		return -1;
 	}
 	if (acc_preparse_req(rq)<0)
 		return -1;
95ee0a3e
 	if(acc_db_set_table_name(rq, (void*)table, NULL)<0) {
 		LM_ERR("cannot set table name\n");
 		return -1;
fb3a5f70
 	}
81c6e0bc
 	if(acc_get_param_value(rq, param)<0)
 		return -1;
8ec042ca
 	env_set_to( rq->to );
81c6e0bc
 	env_set_comment(param);
8ec042ca
 	return acc_db_request(rq);
 }
3efdeefd
 
 int ki_acc_db_request(sip_msg_t *rq, str *comment, str *dbtable)
 {
 	acc_param_t accp;
 
 	if(acc_param_parse(comment, &accp)<0) {
 		LM_ERR("failed execution\n");
 		return -1;
 	}
 	if (acc_preparse_req(rq)<0)
 		return -1;
 	if(acc_db_set_table_name(rq, NULL, dbtable)<0) {
 		LM_ERR("cannot set table name\n");
 		return -1;
 	}
 	env_set_to(rq->to);
 	env_set_comment(&accp);
 	return acc_db_request(rq);
 }
8ec042ca
 
42bdac92
 int ki_acc_request(sip_msg_t *rq, str *comment, str *dbtable)
 {
 	acc_param_t accp;
 	int ret;
 
 	if(acc_param_parse(comment, &accp)<0) {
 		LM_ERR("failed execution\n");
 		return -1;
 	}
 	if (acc_preparse_req(rq)<0)
 		return -1;
 
 	if(acc_db_set_table_name(rq, NULL, dbtable)<0) {
 		LM_ERR("cannot set table name\n");
 		return -1;
 	}
 
 	env_set_to(rq->to);
 	env_set_comment(&accp);
 	env_set_text(ACC_REQUEST, ACC_REQUEST_LEN);
 	ret = acc_log_request(rq);
 	if(ret<0) {
 		LM_ERR("acc log request failed\n");
 	}
 	if(acc_is_db_ready()) {
 		ret = acc_db_request(rq);
 		if(ret<0) {
 			LM_ERR("acc db request failed\n");
 		}
 	}
 
 	return ret;
 }
 
 int w_acc_request(sip_msg_t *rq, char *comment, char *table)
 {
 	str scomment;
 	str stable;
 
 	if(fixup_get_svalue(rq, (gparam_t *)comment, &scomment)<0) {
 		LM_ERR("failed to get comment parameter\n");
 		return -1;
 	}
 	if(fixup_get_svalue(rq, (gparam_t *)table, &stable)<0) {
 		LM_ERR("failed to get table parameter\n");
 		return -1;
 	}
 
 	return ki_acc_request(rq, &scomment, &stable);
 }
 
 
8ec042ca
 /* prepare message and transaction context for later accounting */
 void acc_onreq( struct cell* t, int type, struct tmcb_params *ps )
 {
 	int tmcb_types;
b9f26739
 	int is_invite;
8ec042ca
 
 	if ( ps->req && !skip_cancel(ps->req) &&
cf7a3249
 			( is_acc_on(ps->req) || is_mc_on(ps->req)
 				|| is_acc_prepare_on(ps->req) ) ) {
8ec042ca
 		/* do some parsing in advance */
 		if (acc_preparse_req(ps->req)<0)
 			return;
b9f26739
 		is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0;
8ec042ca
 		/* install additional handlers */
 		tmcb_types =
 			/* report on completed transactions */
 			TMCB_RESPONSE_OUT |
 			/* account e2e acks if configured to do so */
 			((report_ack && is_acc_on(ps->req))?TMCB_E2EACK_IN:0) |
 			/* get incoming replies ready for processing */
 			TMCB_RESPONSE_IN |
 			/* report on missed calls */
989960e3
 			((is_invite && (is_mc_on(ps->req)
 					|| is_acc_prepare_on(ps->req)))?TMCB_ON_FAILURE:0);
aedf352d
 		if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) {
789504a6
 			LM_ERR("cannot register additional callbacks\n");
8ec042ca
 			return;
 		}
 		/* if required, determine request direction */
 		if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) {
789504a6
 			LM_DBG("detected an UPSTREAM req -> flaging it\n");
8ec042ca
 			ps->req->msg_flags |= FL_REQ_UPSTREAM;
 		}
 	}
 }
 
 
 
 /* is this reply of interest for accounting ? */
959ab319
 static inline int should_acc_reply(struct sip_msg *req, struct sip_msg *rpl,
42bdac92
 			int code)
8ec042ca
 {
42bdac92
 	unsigned int i;
959ab319
 
f21554c6
 	LM_DBG("probing acc state - code: %d flags: 0x%x\n", code,
 			(req)?req->flags:0);
f401938a
 	/* negative transactions reported otherwise only if explicitly
8ec042ca
 	 * demanded */
42bdac92
 	if (code >= 300) {
f21554c6
 		if (!is_failed_acc_on(req)) {
 			LM_DBG("failed acc is off\n");
 			return 0;
 		}
f401938a
 		i = 0;
 		while (failed_filter[i] != 0) {
f21554c6
 			if (failed_filter[i] == code) {
 				LM_DBG("acc code in filter: %d\n", code);
 				return 0;
 			}
42bdac92
 			i++;
f401938a
 		}
f21554c6
 		LM_DBG("failed acc is on\n");
f401938a
 		return 1;
42bdac92
 	}
959ab319
 
f21554c6
 	if ( !is_acc_on(req) ) {
 		LM_DBG("acc is off\n");
f401938a
 		return 0;
f21554c6
 	}
f401938a
 
42bdac92
 	if ( code<200 && !(early_media &&
 				parse_headers(rpl,HDR_CONTENTLENGTH_F, 0) == 0 &&
f21554c6
 				rpl->content_length && get_content_length(rpl) > 0)) {
 		LM_DBG("early media acc is off\n");
f401938a
 		return 0;
f21554c6
 	}
959ab319
 
f21554c6
 	LM_DBG("acc is on\n");
42bdac92
 	return 1; /* seed is through, we will account this reply */
8ec042ca
 }
 
 
 
 /* parse incoming replies before cloning */
 static inline void acc_onreply_in(struct cell *t, struct sip_msg *req,
 											struct sip_msg *reply, int code)
 {
 	/* don't parse replies in which we are not interested */
 	/* missed calls enabled ? */
a523d211
 	if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code)
f401938a
 			|| (is_invite(t) && code>=300 && is_mc_on(req))) ) {
 		if(parse_headers(reply, HDR_TO_F, 0)<0) {
 			LM_ERR("failed to parse headers\n");
 		}
8ec042ca
 	}
 }
 
 
 /* initiate a report if we previously enabled MC accounting for this t */
 static inline void on_missed(struct cell *t, struct sip_msg *req,
 											struct sip_msg *reply, int code)
 {
ade20f7c
 	str new_uri_bk = {0, 0};
889a27c9
 	int flags_to_reset = 0;
81b9c83b
 	int br = -1;
8ec042ca
 
f21554c6
 	LM_DBG("preparing to report the record\n");
81b9c83b
 	/* get winning branch index, if set */
ade20f7c
 	if (t->relayed_reply_branch>=0) {
81b9c83b
 		br = t->relayed_reply_branch;
 	} else {
 		if(code>=300) {
 			br = tmb.t_get_picked_branch();
 		}
 	}
 	/* set as new_uri the one from selected branch */
 	if (br>=0) {
ade20f7c
 		new_uri_bk = req->new_uri;
81b9c83b
 		req->new_uri = t->uac[br].uri;
ade20f7c
 		req->parsed_uri_ok = 0;
 	} else {
 		new_uri_bk.len = -1;
 		new_uri_bk.s = 0;
 	}
 
8ec042ca
 	/* set env variables */
 	env_set_to( get_rpl_to(t,reply) );
051300e0
 	env_set_code_status(code, reply);
 	/* for missed calls, we make sure to include the totag if it is locally generated */
 	env_set_totag(t, reply);
8ec042ca
 
 	/* we report on missed calls when the first
 	 * forwarding attempt fails; we do not wish to
f401938a
 	 * report on every attempt; so we clear the flags;
8ec042ca
 	 */
 	if (is_log_mc_on(req)) {
 		env_set_text( ACC_MISSED, ACC_MISSED_LEN);
 		acc_log_request( req );
a7525829
 		flags_to_reset |= 1 << log_missed_flag;
8ec042ca
 	}
 	if (is_db_mc_on(req)) {
95ee0a3e
 		if(acc_db_set_table_name(req, db_table_mc_data, &db_table_mc)<0) {
 			LM_ERR("cannot set missed call db table name\n");
 			return;
 		}
8ec042ca
 		acc_db_request( req );
a7525829
 		flags_to_reset |= 1 << db_missed_flag;
8ec042ca
 	}
56fa1561
 	/* run extra acc engines */
 	acc_run_engines(req, 1, &flags_to_reset);
 
889a27c9
 	/* Reset the accounting missed_flags
 	 * These can't be reset in the blocks above, because
 	 * it would skip accounting if the flags are identical
 	 */
a7525829
 	resetflags(req, flags_to_reset);
889a27c9
 
ade20f7c
 	if (new_uri_bk.len>=0) {
 		req->new_uri = new_uri_bk;
 		req->parsed_uri_ok = 0;
 	}
 
8ec042ca
 }
 
 
15fc8b9c
 extern int _acc_clone_msg;
8ec042ca
 
 /* initiate a report if we previously enabled accounting for this t */
c4c671df
 static void acc_onreply(tm_cell_t *t, sip_msg_t *req, sip_msg_t *reply, int code)
8ec042ca
 {
 	str new_uri_bk;
81b9c83b
 	int br = -1;
e6c0c2f9
 	hdr_field_t *hdr;
c4c671df
 	sip_msg_t *cmsg = 0;
 	int cmsg_len = 0;
 	sip_msg_t *preq = 0;
 	void *mstart;
 	void *mend;
8ec042ca
 
 	/* acc_onreply is bound to TMCB_REPLY which may be called
42bdac92
 	 * from _reply, like when FR hits; we should not miss this
 	 * event for missed calls either */
8ec042ca
 	if (is_invite(t) && code>=300 && is_mc_on(req) )
 		on_missed(t, req, reply, code);
 
a523d211
 	if (!should_acc_reply(req, reply, code))
8ec042ca
 		return;
 
15fc8b9c
 	if(_acc_clone_msg==1) {
c4c671df
 		/* make a clone so eventual new parsed headers in pkg are not visible
 		 * to other processes -- other attributes should be already parsed,
 		 * available in the req structure and propagated by cloning */
 		cmsg = sip_msg_shm_clone(req, &cmsg_len, 1);
 		if(cmsg==NULL) {
 			LM_ERR("failed to clone the request - acc aborted\n");
 			return;
 		}
 		mstart = cmsg;
 		mend = ((char*)cmsg) + cmsg_len;
 		preq = cmsg;
15fc8b9c
 	} else {
c4c671df
 		mstart = t->uas.request;
 		mend = t->uas.end_request;
15fc8b9c
 		preq = req;
 	}
 
81b9c83b
 	/* get winning branch index, if set */
be3227cb
 	if (t->relayed_reply_branch>=0) {
81b9c83b
 		br = t->relayed_reply_branch;
 	} else {
 		if(code>=300) {
 			br = tmb.t_get_picked_branch();
 		}
 	}
 
 	/* for reply processing, set as new_uri the one from selected branch */
 	if (br>=0) {
15fc8b9c
 		new_uri_bk = preq->new_uri;
 		preq->new_uri = t->uac[br].uri;
 		preq->parsed_uri_ok = 0;
8ec042ca
 	} else {
 		new_uri_bk.len = -1;
 		new_uri_bk.s = 0;
 	}
 	/* set env variables */
 	env_set_to( get_rpl_to(t,reply) );
 	env_set_code_status( code, reply);
 
15fc8b9c
 	if ( is_log_acc_on(preq) ) {
8ec042ca
 		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
15fc8b9c
 		acc_log_request(preq);
8ec042ca
 	}
15fc8b9c
 	if (is_db_acc_on(preq)) {
 		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
95ee0a3e
 			LM_ERR("cannot set acc db table name\n");
65571133
 		} else {
15fc8b9c
 			acc_db_request(preq);
95ee0a3e
 		}
8ec042ca
 	}
780c8b8e
 
56fa1561
 	/* run extra acc engines */
15fc8b9c
 	acc_run_engines(preq, 0, NULL);
56fa1561
 
5e761e1b
 	if (new_uri_bk.len>=0) {
c4c671df
 		preq->new_uri = new_uri_bk;
 		preq->parsed_uri_ok = 0;
5e761e1b
 	}
e6c0c2f9
 
 	/* free header's parsed structures that were added by resolving acc attributes */
c4c671df
 	for( hdr=preq->headers ; hdr ; hdr=hdr->next ) {
 		if (hdr->parsed && hdr_allocs_parse(hdr) &&
 					(hdr->parsed<mstart || hdr->parsed>=mend)) {
 			/* header parsed filed doesn't point inside cloned request memory
e6c0c2f9
 			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
 			DBG("removing hdr->parsed %d\n", hdr->type);
 			clean_hdr_field(hdr);
 			hdr->parsed = 0;
 		}
 	}
c4c671df
 	if(cmsg!=NULL) {
 		shm_free(cmsg);
 	}
8ec042ca
 }
 
 
 
 static inline void acc_onack( struct cell* t, struct sip_msg *req,
 		struct sip_msg *ack, int code)
 {
 	if (acc_preparse_req(ack)<0)
 		return;
 
 	/* set env variables */
 	env_set_to( ack->to?ack->to:req->to );
3e84f1c6
 	env_set_code_status( t->uas.status, 0 );
8ec042ca
 
 	if (is_log_acc_on(req)) {
 		env_set_text( ACC_ACKED, ACC_ACKED_LEN);
 		acc_log_request( ack );
 	}
 	if (is_db_acc_on(req)) {
95ee0a3e
 		if(acc_db_set_table_name(ack, db_table_acc_data, &db_table_acc)<0) {
 			LM_ERR("cannot set acc db table name\n");
 			return;
 		}
8ec042ca
 		acc_db_request( ack );
 	}
780c8b8e
 
56fa1561
 	/* run extra acc engines */
58acd28f
 	acc_run_engines(ack, 0, NULL);
8ec042ca
 }
 
 
56fa1561
 /**
  * @brief execute an acc event via a specific engine
  */
 int acc_api_exec(struct sip_msg *rq, acc_engine_t *eng,
 		acc_param_t* comment)
 {
 	acc_info_t inf;
 	if (acc_preparse_req(rq)<0)
 		return -1;
 	env_set_to(rq->to);
 	env_set_comment(comment);
 	memset(&inf, 0, sizeof(acc_info_t));
 	inf.env  = &acc_env;
 	acc_api_set_arrays(&inf);
 	return eng->acc_req(rq, &inf);
 }
 
e3fe8e7f
 /**
  * @brief execute an acc event via a specific engine
  */
 int cdr_api_exec(struct dlg_cell *dlg, struct sip_msg *rq, cdr_engine_t *eng, acc_param_t* comment)
 {
 	cdr_info_t inf;
 	memset(&inf, 0, sizeof(cdr_info_t));
 	cdr_api_set_arrays(&inf);
 	return eng->cdr_write(dlg, rq, &inf);
 }
8ec042ca
 
 static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
 {
989960e3
 	LM_DBG("acc callback called for t(%p) event type %d, reply code %d\n",
 			t, type, ps->code);
8ec042ca
 	if (type&TMCB_RESPONSE_OUT) {
e74cb237
 		env_set_reason(ps->rpl, &ps->send_buf, ps->code);
8ec042ca
 		acc_onreply( t, ps->req, ps->rpl, ps->code);
 	} else if (type&TMCB_E2EACK_IN) {
 		acc_onack( t, t->uas.request, ps->req, ps->code);
 	} else if (type&TMCB_ON_FAILURE) {
 		on_missed( t, ps->req, ps->rpl, ps->code);
 	} else if (type&TMCB_RESPONSE_IN) {
 		acc_onreply_in( t, ps->req, ps->rpl, ps->code);
 	}
f401938a
 }