/** * $Id: items.c 2584 2007-08-08 13:16:30Z miconda $ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2005 Voice Sistem SRL * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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 * * History: * -------- * 2004-10-20 - added header name specifier (ramona) * 2005-06-14 - added avp name specifier (ramona) * 2005-06-18 - added color printing support via escape sequesnces * contributed by Ingo Flaschberger (daniel) * 2005-06-22 - created this file from modules/xlog/xl_lib.c (daniel) */ #include #include #include #include #include #include "dprint.h" #include "mem/mem.h" #include "mem/shm_mem.h" #include "ut.h" #include "trim.h" #include "dset.h" #include "usr_avp.h" #include "errinfo.h" #include "parser/parse_from.h" #include "parser/parse_uri.h" #include "parser/parse_hname2.h" #include "parser/parse_content.h" #include "parser/parse_refer_to.h" #include "parser/parse_rpid.h" #include "parser/parse_diversion.h" #include "parser/parse_ppi.h" #include "parser/parse_pai.h" #include "parser/digest/digest.h" #include "script_var.h" #include "transformations.h" static str str_null = { "", 6 }; static str str_empty = { "", 0 }; static str str_marker = { ITEM_MARKER_STR, 1 }; static str str_udp = { "UDP", 3 }; static str str_5060 = { "5060", 4 }; unsigned int _it_msg_id = 0; time_t msg_tm = 0; int cld_pid = 0; #define ITEM_FIELD_DELIM ", " #define ITEM_FIELD_DELIM_LEN (sizeof(ITEM_FIELD_DELIM) - 1) #define LOCAL_BUF_SIZE 511 static char local_buf[LOCAL_BUF_SIZE+1]; int xl_get_null(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs = str_empty; res->ri = 0; res->flags = XL_VAL_NULL; return 0; } /* static int xl_get_empty(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs = str_empty; res->ri = 0; res->flags = XL_VAL_STR|XL_VAL_INT|XL_VAL_EMPTY; return 0; } */ static int xl_get_marker(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs = str_marker; res->ri = (int)str_marker.s[0]; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_udp(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs = str_udp; res->ri = PROTO_UDP; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_5060(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs = str_5060; res->ri = 5060; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_pid(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; if(msg==NULL || res==NULL) return -1; if(cld_pid == 0) cld_pid = (int)getpid(); ch = int2str(cld_pid, &l); res->rs.s = ch; res->rs.len = l; res->ri = cld_pid; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } extern int return_code; static int xl_get_return_code(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *s = NULL; if(msg==NULL || res==NULL) return -1; s = sint2str(return_code, &l); res->rs.s = s; res->rs.len = l; res->ri = return_code; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } static int xl_get_times(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; if(msg==NULL || res==NULL) return -1; if(_it_msg_id != msg->id || msg_tm==0) { msg_tm = time(NULL); _it_msg_id = msg->id; } ch = int2str(msg_tm, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)msg_tm; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } static int xl_get_timef(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { char *ch = NULL; if(msg==NULL || res==NULL) return -1; if(_it_msg_id != msg->id || msg_tm==0) { msg_tm = time(NULL); _it_msg_id = msg->id; } ch = ctime(&msg_tm); res->rs.s = ch; res->rs.len = strlen(ch)-1; res->ri = (int)msg_tm; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_msgid(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; if(msg==NULL || res==NULL) return -1; ch = int2str(msg->id, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)msg->id; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } static int xl_get_method(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REQUEST) { res->rs.s = msg->first_line.u.request.method.s; res->rs.len = msg->first_line.u.request.method.len; res->ri = (int)msg->first_line.u.request.method_value; } else { if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || (msg->cseq==NULL))) { LOG(L_ERR, "xl_get_method: ERROR cannot parse CSEQ header\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = get_cseq(msg)->method.s; res->rs.len = get_cseq(msg)->method.len; res->ri = get_cseq(msg)->method_id; } res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_status(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) { res->rs.s = msg->first_line.u.reply.status.s; res->rs.len = msg->first_line.u.reply.status.len; } else return xl_get_null(msg, res, param, flags); res->ri = (int)msg->first_line.u.reply.statuscode; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; return 0; } static int xl_get_reason(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) { res->rs.s = msg->first_line.u.reply.reason.s; res->rs.len = msg->first_line.u.reply.reason.len; } else return xl_get_null(msg, res, param, flags); res->flags = XL_VAL_STR; return 0; } static int xl_get_ruri(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */ return xl_get_null(msg, res, param, flags); if(msg->parsed_uri_ok==0 /* R-URI not parsed*/ && parse_sip_msg_uri(msg)<0) { LOG(L_ERR, "xl_get_ruri: ERROR while parsing the R-URI\n"); return xl_get_null(msg, res, param, flags); } if (msg->new_uri.s!=NULL) { res->rs.s = msg->new_uri.s; res->rs.len = msg->new_uri.len; } else { res->rs.s = msg->first_line.u.request.uri.s; res->rs.len = msg->first_line.u.request.uri.len; } res->flags = XL_VAL_STR; return 0; } static int xl_get_ouri(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */ return xl_get_null(msg, res, param, flags); if(msg->parsed_orig_ruri_ok==0 /* orig R-URI not parsed*/ && parse_orig_ruri(msg)<0) { LOG(L_ERR, "xl_get_ouri: ERROR while parsing the R-URI\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->first_line.u.request.uri.s; res->rs.len = msg->first_line.u.request.uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_xuri_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, struct sip_uri *parsed_uri, int flags) { if(param->val.len==1) /* username */ { if(parsed_uri->user.s==NULL || parsed_uri->user.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = parsed_uri->user.s; res->rs.len = parsed_uri->user.len; res->flags = XL_VAL_STR; } else if(param->val.len==2) /* domain */ { res->rs.s = parsed_uri->host.s; res->rs.len = parsed_uri->host.len; res->flags = XL_VAL_STR; } else if(param->val.len==3) /* port */ { if(parsed_uri->port.s==NULL) return xl_get_5060(msg, res, param, flags); res->rs.s = parsed_uri->port.s; res->rs.len = parsed_uri->port.len; res->ri = (int)parsed_uri->port_no; res->flags = XL_VAL_STR|XL_VAL_INT; } else if(param->val.len==4) /* protocol */ { if(parsed_uri->transport_val.s==NULL) return xl_get_udp(msg, res, param, flags); res->rs.s = parsed_uri->transport_val.s; res->rs.len = parsed_uri->transport_val.len; res->ri = (int)parsed_uri->proto; res->flags = XL_VAL_STR|XL_VAL_INT; } else { LOG(L_ERR, "xl_get_xuri_attr: unknown specifier\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_ruri_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */ return xl_get_null(msg, res, param, flags); if(msg->parsed_uri_ok==0 /* R-URI not parsed*/ && parse_sip_msg_uri(msg)<0) { LOG(L_ERR, "xl_get_ruri_attr: ERROR while parsing the R-URI\n"); return xl_get_null(msg, res, param, flags); } return xl_get_xuri_attr(msg, res, param, &(msg->parsed_uri), flags); } static int xl_get_ouri_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */ return xl_get_null(msg, res, param, flags); if(msg->parsed_orig_ruri_ok==0 /* orig R-URI not parsed*/ && parse_orig_ruri(msg)<0) { LOG(L_ERR, "xl_get_ouri: ERROR while parsing the R-URI\n"); return xl_get_null(msg, res, param, flags); } return xl_get_xuri_attr(msg, res, param, &(msg->parsed_orig_ruri), flags); } static int xl_get_contact(struct sip_msg* msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->contact==NULL && parse_headers(msg, HDR_CONTACT_F, 0)==-1) { DBG("xl_get_contact: no contact header\n"); return xl_get_null(msg, res, param, flags); } if(!msg->contact || !msg->contact->body.s || msg->contact->body.len<=0) { DBG("xl_get_contact: no contact header!\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->contact->body.s; res->rs.len = msg->contact->body.len; // res->s = ((struct to_body*)msg->contact->parsed)->uri.s; // res->len = ((struct to_body*)msg->contact->parsed)->uri.len; res->flags = XL_VAL_STR; return 0; } extern err_info_t _oser_err_info; static int xl_get_errinfo_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; if(msg==NULL || res==NULL) return -1; if(param->val.len==0) /* class */ { ch = int2str(_oser_err_info.eclass, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)_oser_err_info.eclass; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; } else if(param->val.len==1) /* level */ { ch = int2str(_oser_err_info.level, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)_oser_err_info.level; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; } else if(param->val.len==2) /* info */ { if(_oser_err_info.info.s==NULL) xl_get_null(msg, res, param, flags); res->rs.s = _oser_err_info.info.s; res->rs.len = _oser_err_info.info.len; res->flags = XL_VAL_STR; } else if(param->val.len==3) /* rcode */ { ch = int2str(_oser_err_info.rcode, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)_oser_err_info.rcode; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; } else if(param->val.len==4) /* rreason */ { if(_oser_err_info.rreason.s==NULL) xl_get_null(msg, res, param, flags); res->rs.s = _oser_err_info.rreason.s; res->rs.len = _oser_err_info.rreason.len; res->flags = XL_VAL_STR; } else { DBG("xl_get_errinfo_attr: invalid attribute!\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_from_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct sip_uri *uri; if(msg==NULL || res==NULL) return -1; if(parse_from_header(msg)<0) { LOG(L_ERR, "xl_get_from_attr: ERROR cannot parse FROM header\n"); return xl_get_null(msg, res, param, flags); } if(msg->from==NULL || get_from(msg)==NULL) return xl_get_null(msg, res, param, flags); if(param->val.len==1) /* uri */ { res->rs.s = get_from(msg)->uri.s; res->rs.len = get_from(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } if(param->val.len==4) /* tag */ { if(get_from(msg)->tag_value.s==NULL||get_from(msg)->tag_value.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = get_from(msg)->tag_value.s; res->rs.len = get_from(msg)->tag_value.len; res->flags = XL_VAL_STR; return 0; } if(param->val.len==5) /* display name */ { if(get_from(msg)->display.s==NULL||get_from(msg)->display.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = get_from(msg)->display.s; res->rs.len = get_from(msg)->display.len; res->flags = XL_VAL_STR; return 0; } if((uri=parse_from_uri(msg))==NULL) return xl_get_null(msg, res, param, flags); if(param->val.len==2) /* username */ { if(uri->user.s==NULL || uri->user.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = uri->user.s; res->rs.len = uri->user.len; res->flags = XL_VAL_STR; } else if(param->val.len==3) /* domain */ { res->rs.s = uri->host.s; res->rs.len = uri->host.len; res->flags = XL_VAL_STR; } else { LOG(L_ERR, "xl_get_from_attr: unknown specifier\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_to_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct sip_uri *uri; if(msg==NULL || res==NULL) return -1; if(msg->to==NULL && parse_headers(msg, HDR_TO_F, 0)==-1) { LOG(L_ERR, "xl_get_to_attr: ERROR cannot parse TO header\n"); return xl_get_null(msg, res, param, flags); } if(msg->to==NULL || get_to(msg)==NULL) return xl_get_null(msg, res, param, flags); if(param->val.len==1) /* uri */ { res->rs.s = get_to(msg)->uri.s; res->rs.len = get_to(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } if(param->val.len==4) /* tag */ { if (get_to(msg)->tag_value.s==NULL||get_to(msg)->tag_value.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = get_to(msg)->tag_value.s; res->rs.len = get_to(msg)->tag_value.len; res->flags = XL_VAL_STR; return 0; } if(param->val.len==5) /* display name */ { if(get_to(msg)->display.s==NULL||get_to(msg)->display.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = get_to(msg)->display.s; res->rs.len = get_to(msg)->display.len; res->flags = XL_VAL_STR; return 0; } if((uri=parse_to_uri(msg))==NULL) return xl_get_null(msg, res, param, flags); if(param->val.len==2) /* username */ { if(uri->user.s==NULL || uri->user.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = uri->user.s; res->rs.len = uri->user.len; res->flags = XL_VAL_STR; } else if(param->val.len==3) /* domain */ { res->rs.s = uri->host.s; res->rs.len = uri->host.len; res->flags = XL_VAL_STR; } else { LOG(L_ERR, "xl_get_to_attr: unknown specifier\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_cseq(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || (msg->cseq==NULL)) ) { LOG(L_ERR, "xl_get_cseq: ERROR cannot parse CSEQ header\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = get_cseq(msg)->number.s; res->rs.len = get_cseq(msg)->number.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_msg_buf(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = msg->buf; res->rs.len = msg->len; res->flags = XL_VAL_STR; return 0; } static int xl_get_msg_len(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = int2str(msg->len, &res->rs.len); res->ri = (int)msg->len; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_flags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = int2str(msg->flags, &res->rs.len); res->ri = (int)msg->flags; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static inline char* int_to_8hex(int val) { unsigned short digit; int i; static char outbuf[9]; outbuf[8] = '\0'; for(i=0; i<8; i++) { if(val!=0) { digit = val & 0x0f; outbuf[7-i] = digit >= 10 ? digit + 'a' - 10 : digit + '0'; val >>= 4; } else outbuf[7-i] = '0'; } return outbuf; } static int xl_get_hexflags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = int_to_8hex(msg->flags); res->rs.len = 8; res->ri = (int)msg->flags; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_bflags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param,int flags) { if(res==NULL) return -1; res->ri = (int)getb0flags(); res->rs.s = int2str( res->ri, &res->rs.len); res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_hexbflags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(res==NULL) return -1; res->ri = (int)getb0flags(); res->rs.s = int_to_8hex(res->ri); res->rs.len = 8; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_sflags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param,int flags) { if(res==NULL) return -1; res->ri = (int)getsflags(); res->rs.s = int2str( res->ri, &res->rs.len); res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_hexsflags(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(res==NULL) return -1; res->ri = (int)getsflags(); res->rs.s = int_to_8hex(res->ri); res->rs.len = 8; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_callid(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) || (msg->callid==NULL)) ) { LOG(L_ERR, "xl_get_callid: ERROR cannot parse Call-Id header\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->callid->body.s; res->rs.len = msg->callid->body.len; trim(&res->rs); res->flags = XL_VAL_STR; return 0; } static int xl_get_srcip(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = ip_addr2a(&msg->rcv.src_ip); res->rs.len = strlen(res->rs.s); res->flags = XL_VAL_STR; return 0; } static int xl_get_srcport(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; if(msg==NULL || res==NULL) return -1; ch = int2str(msg->rcv.src_port, &l); res->rs.s = ch; res->rs.len = l; res->ri = (int)msg->rcv.src_port; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_rcvip(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->rcv.bind_address==NULL || msg->rcv.bind_address->address_str.s==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = msg->rcv.bind_address->address_str.s; res->rs.len = msg->rcv.bind_address->address_str.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_rcvport(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->rcv.bind_address==NULL || msg->rcv.bind_address->port_no_str.s==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = msg->rcv.bind_address->port_no_str.s; res->rs.len = msg->rcv.bind_address->port_no_str.len; res->ri = (int)msg->rcv.bind_address->port_no; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } static int xl_get_force_sock(struct sip_msg *msg, xl_value_t *res, xl_param_t *param,int flags) { if(msg==NULL || res==NULL) return -1; if (msg->force_send_socket==0) return xl_get_null(msg, res, param, flags); res->rs = msg->force_send_socket->sock_str; res->flags = XL_VAL_STR; return 0; } static int xl_get_useragent(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->user_agent==NULL && ((parse_headers(msg, HDR_USERAGENT_F, 0)==-1) || (msg->user_agent==NULL))) { DBG("xl_get_useragent: User-Agent header not found\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->user_agent->body.s; res->rs.len = msg->user_agent->body.len; trim(&res->rs); res->flags = XL_VAL_STR; return 0; } static int xl_get_refer_to(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(parse_refer_to_header(msg)==-1) { LOG(L_ERR, "xl_get_refer_to: ERROR cannot parse Refer-To header\n"); return xl_get_null(msg, res, param, flags); } if(msg->refer_to==NULL || get_refer_to(msg)==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = get_refer_to(msg)->uri.s; res->rs.len = get_refer_to(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_diversion(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(parse_diversion_header(msg)==-1) { LOG(L_ERR, "xl_get_diversion: ERROR cannot parse Diversion header\n"); return xl_get_null(msg, res, param, flags); } if(msg->diversion==NULL || get_diversion(msg)==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = get_diversion(msg)->uri.s; res->rs.len = get_diversion(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_rpid(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(parse_rpid_header(msg)==-1) { LOG(L_ERR, "xl_get_rpid: ERROR cannot parse RPID header\n"); return xl_get_null(msg, res, param, flags); } if(msg->rpid==NULL || get_rpid(msg)==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = get_rpid(msg)->uri.s; res->rs.len = get_rpid(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_ppi_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct sip_uri *uri; if(msg==NULL || res==NULL) return -1; if(parse_ppi_header(msg) < 0) { LOG(L_ERR, "xl_get_ppi_attr: ERROR cannot parse P-Preferred-Identity " "header\n"); return xl_get_null(msg, res, param, flags); } if(msg->ppi == NULL || get_ppi(msg) == NULL) return xl_get_null(msg, res, param, flags); if(param->val.len == 1) { /* uri */ res->rs.s = get_ppi(msg)->uri.s; res->rs.len = get_ppi(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } if(param->val.len==4) { /* display name */ if(get_ppi(msg)->display.s == NULL || get_ppi(msg)->display.len <= 0) return xl_get_null(msg, res, param, flags); res->rs.s = get_ppi(msg)->display.s; res->rs.len = get_ppi(msg)->display.len; res->flags = XL_VAL_STR; return 0; } if((uri=parse_ppi_uri(msg))==NULL) return xl_get_null(msg, res, param, flags); if(param->val.len==2) { /* username */ if(uri->user.s==NULL || uri->user.len<=0) return xl_get_null(msg, res, param, flags); res->rs.s = uri->user.s; res->rs.len = uri->user.len; res->flags = XL_VAL_STR; } else if(param->val.len==3) { /* domain */ res->rs.s = uri->host.s; res->rs.len = uri->host.len; res->flags = XL_VAL_STR; } else { LOG(L_ERR, "xl_get_ppi_attr: unknown specifier\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_pai(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(parse_pai_header(msg)==-1) { LOG(L_ERR, "xl_get_pai: ERROR cannot parse P-Asserted-Identity header\n"); return xl_get_null(msg, res, param, flags); } if(msg->pai==NULL || get_pai(msg)==NULL) return xl_get_null(msg, res, param, flags); res->rs.s = get_pai(msg)->uri.s; res->rs.len = get_pai(msg)->uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_dset(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = print_dset(msg, &res->rs.len); if ((res->rs.s) == NULL) return xl_get_null(msg, res, param, flags); res->rs.len -= CRLF_LEN; res->flags = XL_VAL_STR; return 0; } static int xl_get_dsturi(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if (msg->dst_uri.s == NULL) return xl_get_null(msg, res, param, flags); res->rs.s = msg->dst_uri.s; res->rs.len = msg->dst_uri.len; res->flags = XL_VAL_STR; return 0; } static int xl_get_dsturi_attr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct sip_uri uri; if(msg==NULL || res==NULL) return -1; if (msg->dst_uri.s == NULL) return xl_get_null(msg, res, param, flags); if(parse_uri(msg->dst_uri.s, msg->dst_uri.len, &uri)!=0) { LOG(L_ERR, "xl_get_dsturi_attr: ERROR cannot parse dst uri\n"); return xl_get_null(msg, res, param, flags); } if(param->val.len==1) /* domain */ { res->rs.s = uri.host.s; res->rs.len = uri.host.len; res->flags = XL_VAL_STR; } else if(param->val.len==2) /* port */ { if(uri.port.s==NULL) return xl_get_5060(msg, res, param, flags); res->rs.s = uri.port.s; res->rs.len = uri.port.len; res->ri = (int)uri.port_no; res->flags = XL_VAL_STR|XL_VAL_INT; return 0; } else if(param->val.len==3) /* proto */ { if(uri.transport_val.s==NULL) return xl_get_udp(msg, res, param, flags); res->rs.s = uri.transport_val.s; res->rs.len = uri.transport_val.len; res->ri = (int)uri.proto; res->flags = XL_VAL_STR|XL_VAL_INT; } else { LOG(L_ERR, "xl_get_dsturi_attr: invalid specifier\n"); return xl_get_null(msg, res, param, flags); } return 0; } static int xl_get_content_type(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->content_type==NULL && ((parse_headers(msg, HDR_CONTENTTYPE_F, 0)==-1) || (msg->content_type==NULL))) { DBG("xl_get_content_type: Content-Type header not found\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->content_type->body.s; res->rs.len = msg->content_type->body.len; trim(&res->rs); res->flags = XL_VAL_STR; return 0; } static int xl_get_content_length(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; if(msg->content_length==NULL && ((parse_headers(msg, HDR_CONTENTLENGTH_F, 0)==-1) || (msg->content_length==NULL))) { DBG("xl_get_content_length: Content-Length header not found\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = msg->content_length->body.s; res->rs.len = msg->content_length->body.len; trim(&res->rs); res->ri = (int)(long)msg->content_length->parsed; res->flags = XL_VAL_STR | XL_VAL_INT; return 0; } static int xl_get_msg_body(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { if(msg==NULL || res==NULL) return -1; res->rs.s = get_body( msg ); if ((res->rs.s) == NULL) return xl_get_null(msg, res, param, flags); if (!msg->content_length) { LOG(L_ERR,"xl_get_msg_body: ERROR no Content-Length header found!\n"); return xl_get_null(msg, res, param, flags); } res->rs.len = get_content_length(msg); res->flags = XL_VAL_STR; return 0; } static int xl_get_authattr(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct hdr_field *hdr; if(msg==NULL || res==NULL) return -1; if ((msg->REQ_METHOD == METHOD_ACK) || (msg->REQ_METHOD == METHOD_CANCEL)) return xl_get_null(msg, res, param, flags); if ((parse_headers(msg, HDR_PROXYAUTH_F|HDR_AUTHORIZATION_F, 0)==-1) || (msg->proxy_auth==0 && msg->authorization==0)) { LOG(L_ERR, "xl_get_authattr: Error while parsing headers\n"); return -1; } hdr = (msg->proxy_auth==0)?msg->authorization:msg->proxy_auth; if(parse_credentials(hdr)!=0) return xl_get_null(msg, res, param, flags); if(param->val.len==2) { res->rs.s = ((auth_body_t*)(hdr->parsed))->digest.realm.s; res->rs.len = ((auth_body_t*)(hdr->parsed))->digest.realm.len; } else { res->rs.s = ((auth_body_t*)(hdr->parsed))->digest.username.user.s; res->rs.len = ((auth_body_t*)(hdr->parsed))->digest.username.user.len; } res->flags = XL_VAL_STR; return 0; } static inline str *cred_user(struct sip_msg *rq) { struct hdr_field* h; auth_body_t* cred; get_authorized_cred(rq->proxy_auth, &h); if (!h) get_authorized_cred(rq->authorization, &h); if (!h) return 0; cred=(auth_body_t*)(h->parsed); if (!cred || !cred->digest.username.user.len) return 0; return &cred->digest.username.user; } static inline str *cred_realm(struct sip_msg *rq) { str* realm; struct hdr_field* h; auth_body_t* cred; get_authorized_cred(rq->proxy_auth, &h); if (!h) get_authorized_cred(rq->authorization, &h); if (!h) return 0; cred=(auth_body_t*)(h->parsed); if (!cred) return 0; realm = GET_REALM(&cred->digest); if (!realm->len || !realm->s) { return 0; } return realm; } static int xl_get_acc_username(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { static char buf[MAX_URI_SIZE]; str* user; str* realm; struct sip_uri puri; struct to_body* from; /* try to take it from credentials */ user = cred_user(msg); if (user) { realm = cred_realm(msg); if (realm) { res->rs.len = user->len+1+realm->len; if (res->rs.len > MAX_URI_SIZE) { LOG(L_ERR, "xl_get_acc_username: URI too long\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = buf; memcpy(res->rs.s, user->s, user->len); (res->rs.s)[user->len] = '@'; memcpy(res->rs.s+user->len+1, realm->s, realm->len); } else { res->rs.len = user->len; res->rs.s = user->s; } } else { /* from from uri */ if(parse_from_header(msg)<0) { LOG(L_ERR, "xl_get_acc_username: ERROR cannot parse FROM header\n"); return xl_get_null(msg, res, param, flags); } if (msg->from && (from=get_from(msg)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "xl_get_acc_username: Bad From URI\n"); return xl_get_null(msg, res, param, flags); } res->rs.len = puri.user.len + 1 + puri.host.len; if (res->rs.len > MAX_URI_SIZE) { LOG(L_ERR, "xl_acc__username: URI too long\n"); return xl_get_null(msg, res, param, flags); } res->rs.s = buf; memcpy(res->rs.s, puri.user.s, puri.user.len); (res->rs.s)[puri.user.len] = '@'; memcpy(res->rs.s + puri.user.len + 1, puri.host.s, puri.host.len); } else { res->rs.len = 0; res->rs.s = 0; } } res->flags = XL_VAL_STR; return 0; } #define COL_BUF 10 #define append_sstring(p, end, str) \ do{\ if ((p)+(sizeof(str)-1)<=(end)){\ memcpy((p), str, sizeof(str)-1); \ (p)+=sizeof(str)-1; \ }else{ \ /* overflow */ \ LOG(L_ERR, "append_sstring overflow\n"); \ goto error;\ } \ } while(0) static int xl_get_color(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { static char color[COL_BUF]; char* p; char* end; p = color; end = p + COL_BUF; /* excape sequenz */ append_sstring(p, end, "\033["); if(param->val.s[0]!='_') { if (islower((int)param->val.s[0])) { /* normal font */ append_sstring(p, end, "0;"); } else { /* bold font */ append_sstring(p, end, "1;"); param->val.s[0] += 32; } } /* foreground */ switch(param->val.s[0]) { case 'x': append_sstring(p, end, "39;"); break; case 's': append_sstring(p, end, "30;"); break; case 'r': append_sstring(p, end, "31;"); break; case 'g': append_sstring(p, end, "32;"); break; case 'y': append_sstring(p, end, "33;"); break; case 'b': append_sstring(p, end, "34;"); break; case 'p': append_sstring(p, end, "35;"); break; case 'c': append_sstring(p, end, "36;"); break; case 'w': append_sstring(p, end, "37;"); break; default: LOG(L_ERR, "xl_get_color: exit foreground\n"); return xl_get_null(msg, res, param, flags); } /* background */ switch(param->val.s[1]) { case 'x': append_sstring(p, end, "49"); break; case 's': append_sstring(p, end, "40"); break; case 'r': append_sstring(p, end, "41"); break; case 'g': append_sstring(p, end, "42"); break; case 'y': append_sstring(p, end, "43"); break; case 'b': append_sstring(p, end, "44"); break; case 'p': append_sstring(p, end, "45"); break; case 'c': append_sstring(p, end, "46"); break; case 'w': append_sstring(p, end, "47"); break; default: LOG(L_ERR, "xl_get_color: exit background\n"); return xl_get_null(msg, res, param, flags); } /* end */ append_sstring(p, end, "m"); res->rs.s = color; res->rs.len = p-color; res->flags = XL_VAL_STR; return 0; error: return -1; } static int xl_get_branch(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { str branch; qvalue_t q; if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) return xl_get_null(msg, res, param, flags); branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0); if (!branch.s) { return xl_get_null(msg, res, param, flags); } res->rs.s = branch.s; res->rs.len = branch.len; res->flags = XL_VAL_STR; return 0; } #define Q_PARAM ">;q=" #define Q_PARAM_LEN (sizeof(Q_PARAM) - 1) static int xl_get_branches(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { str uri; qvalue_t q; int len, cnt, i; unsigned int qlen; char *p, *qbuf; if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) return xl_get_null(msg, res, param, flags); cnt = len = 0; while ((uri.s = get_branch(cnt, &uri.len, &q, 0, 0, 0, 0))) { cnt++; len += uri.len; if (q != Q_UNSPECIFIED) { len += 1 + Q_PARAM_LEN + len_q(q); } } if (cnt == 0) return xl_get_null(msg, res, param, flags); len += (cnt - 1) * ITEM_FIELD_DELIM_LEN; if (len + 1 > LOCAL_BUF_SIZE) { LOG(L_ERR, "ERROR:xl_get_branches: local buffer length exceeded\n"); return xl_get_null(msg, res, param, flags); } i = 0; p = local_buf; while ((uri.s = get_branch(i, &uri.len, &q, 0, 0, 0, 0))) { if (i) { memcpy(p, ITEM_FIELD_DELIM, ITEM_FIELD_DELIM_LEN); p += ITEM_FIELD_DELIM_LEN; } if (q != Q_UNSPECIFIED) { *p++ = '<'; } memcpy(p, uri.s, uri.len); p += uri.len; if (q != Q_UNSPECIFIED) { memcpy(p, Q_PARAM, Q_PARAM_LEN); p += Q_PARAM_LEN; qbuf = q2str(q, &qlen); memcpy(p, qbuf, qlen); p += qlen; } i++; } res->rs.s = &(local_buf[0]); res->rs.len = len; res->flags = XL_VAL_STR; return 0; } static int xl_get_script_var(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { int l = 0; char *ch = NULL; script_var_t *sv=NULL; if(msg==NULL || res==NULL) return -1; if(param==NULL || param->data==0) return xl_get_null(msg, res, param, flags); sv= (script_var_t*)param->data; if(sv->v.flags&&VAR_VAL_STR) { res->rs = sv->v.value.s; res->flags = XL_VAL_STR; } else { ch = int2str(sv->v.value.n, &l); res->rs.s = ch; res->rs.len = l; res->ri = sv->v.value.n; res->flags = XL_VAL_STR|XL_VAL_INT|XL_TYPE_INT; } return 0; } #define ITEM_PRINT_ALL -2 #define ITEM_PRINT_LAST -1 static int xl_get_header(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { struct hdr_field *hf, *hf0; char *p; int lidx; int found; if(msg==NULL || res==NULL) return -1; if(param==NULL || param->val.len==0) return xl_get_null(msg, res, param, flags); hf0 = NULL; p = local_buf; /* we need to be sure we have parsed all headers */ if(parse_headers(msg, HDR_EOH_F, 0)<0) { LOG(L_ERR,"xl_get_header: error parsing headers\n"); return xl_get_null(msg, res, param, flags); } lidx = param->ind; found = 0; for (hf=msg->headers; hf; hf=hf->next) { if(param->val.s==NULL) { if (param->val.len!=hf->type) continue; } else { if (hf->name.len!=param->val.len) continue; if (strncasecmp(hf->name.s, param->val.s, hf->name.len)!=0) continue; } hf0 = hf; if(lidx==ITEM_PRINT_ALL) { if(p!=local_buf) { if(p-local_buf+ITEM_FIELD_DELIM_LEN+1>LOCAL_BUF_SIZE) { LOG(L_ERR, "ERROR:xl_get_header: local buffer length exceeded\n"); return xl_get_null(msg, res, param, flags); } memcpy(p, ITEM_FIELD_DELIM, ITEM_FIELD_DELIM_LEN); p += ITEM_FIELD_DELIM_LEN; } if(p-local_buf+hf0->body.len+1>LOCAL_BUF_SIZE) { LOG(L_ERR, "ERROR:xl_get_header: local buffer length exceeded!\n"); return xl_get_null(msg, res, param, flags); } memcpy(p, hf0->body.s, hf0->body.len); p += hf0->body.len; continue; } if(lidx==0) { found = 1; goto done; } if(lidx>0) lidx--; } done: res->flags = XL_VAL_STR; if(lidx==ITEM_PRINT_ALL) { if(p != local_buf) { *p = 0; res->rs.s = local_buf; res->rs.len = p - local_buf; return 0; } else return xl_get_null(msg, res, param, flags); } if(hf0!=NULL && (found==1 || lidx==ITEM_PRINT_LAST)) { res->rs.s = hf0->body.s; res->rs.len = hf0->body.len; trim(&res->rs); return 0; } return xl_get_null(msg, res, param, flags); } static int xl_get_avp(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { unsigned short name_type; int_str avp_name; int_str avp_value; struct usr_avp *avp; char *p; int lidx; str s = {0, 0}; if(msg==NULL || res==NULL) return -1; if(param==NULL || param->val.len==0) return xl_get_null(msg, res, param, flags); if(param->val.s==NULL) { name_type = flags>>16; avp_name.n = param->val.len; } else { name_type = flags>>16; avp_name.s = param->val; } p = local_buf; if ((avp=search_first_avp(name_type, avp_name, &avp_value, 0))==0) return xl_get_null(msg, res, param, flags); lidx = param->ind; do { /* todo: optimization for last avp !!! */ if(lidx==0 || lidx==ITEM_PRINT_ALL || lidx==ITEM_PRINT_LAST) { if(avp->flags & AVP_VAL_STR) { s.s = avp_value.s.s; s.len = avp_value.s.len; } else { s.s = int2str(avp_value.n, &s.len); } } if(lidx==ITEM_PRINT_ALL) { if(p!=local_buf) { if(p-local_buf+ITEM_FIELD_DELIM_LEN+1>LOCAL_BUF_SIZE) { LOG(L_ERR, "ERROR:xl_get_avp: local buffer length exceeded\n"); return xl_get_null(msg, res, param, flags); } memcpy(p, ITEM_FIELD_DELIM, ITEM_FIELD_DELIM_LEN); p += ITEM_FIELD_DELIM_LEN; } if(p-local_buf+s.len+1>LOCAL_BUF_SIZE) { LOG(L_ERR, "ERROR:xl_get_header: local buffer length exceeded!\n"); return xl_get_null(msg, res, param, flags); } memcpy(p, s.s, s.len); p += s.len; continue; } if(lidx==0) goto done; if(lidx>0) lidx--; if(lidx!=ITEM_PRINT_LAST) { s.s = NULL; s.len = 0; } } while ((avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0); done: res->flags = XL_VAL_STR; if(lidx==ITEM_PRINT_ALL) { *p = 0; res->rs.s = local_buf; res->rs.len = p - local_buf; return 0; } else { if(avp && !(avp->flags&AVP_VAL_STR)) { res->ri = avp_value.n; res->flags |= XL_VAL_INT|XL_TYPE_INT; } } if(s.s==NULL || lidx>0) return xl_get_null(msg, res, param, flags); res->rs.s = s.s; res->rs.len = s.len; return 0; } int xl_update_hdrname(xl_spec_p e) { char c; struct hdr_field hdr; if(e==NULL || e->p.val.s==NULL || e->p.val.len<=0) goto error; /* optimize for known headers -- fake header name */ c = e->p.val.s[e->p.val.len]; e->p.val.s[e->p.val.len] = ':'; e->p.val.len++; /* ugly hack for compact header names -- !!fake length!! * -- parse_hname2 expects name buffer length >= 4 */ if (parse_hname2(e->p.val.s, e->p.val.s + ((e->p.val.len<4)?4:e->p.val.len), &hdr)==0) { LOG(L_ERR,"xl_parse_name: error parsing header name\n"); goto error; } e->p.val.len--; e->p.val.s[e->p.val.len] = c; if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) { LOG(L_INFO,"INFO:xl_parse_name: using " "hdr type (%d) instead of <%.*s>\n", hdr.type, e->p.val.len, e->p.val.s); e->p.val.len = hdr.type; e->p.val.s = NULL; } return 0; error: return -1; } char* xl_parse_index(char *s, int *ind) { char *p; if(s==NULL || ind==NULL) return NULL; *ind = 0; p = s; /* check if we have index */ if(*p != ITEM_LIBRACKET) return p; p++; if(*p=='-') { p++; if(*p!='1') { LOG(L_ERR, "xl_parse_index: error" " parsing format [%s] -- only -1 is accepted" " as a negative index\n", p); goto error; } *ind = ITEM_PRINT_LAST; p++; } else if (*p=='*') { *ind = ITEM_PRINT_ALL; p++; } else { while(*p>='0' && *p<='9') { *ind = (*ind) * 10 + *p - '0'; p++; } } if(*p != ITEM_RIBRACKET) { LOG(L_ERR, "xl_parse_index: error parsing format" " [%s] expecting '%c'\n", p, ITEM_RIBRACKET); goto error; } p++; return p; error: return NULL; } char* xl_parse_name(char *s, xl_spec_p e) { char *p; if(s==NULL || e==NULL) return NULL; p = s; e->p.val.s = p; while(*p && *p!=ITEM_RNBRACKET && *p!=ITEM_LIBRACKET) p++; if(p == e->p.val.s) { LOG(L_ERR, "xl_parse_name: error parsing format - empty name" " [%s]\n", e->p.val.s); goto error; } e->p.val.len = p - e->p.val.s; if(*p==ITEM_RNBRACKET) goto done; if(*p=='\0') { LOG(L_ERR, "xl_parse_name: error parsing format - in name" " [%s] expecting '%c'\n", e->p.val.s, ITEM_RNBRACKET); goto error; } /* check if we have index */ p = xl_parse_index(p, &(e->p.ind)); if(p==NULL) goto error; if(*p != ITEM_RNBRACKET) { LOG(L_ERR, "xl_parse_name: error parsing format" " [%s] expecting '%c'!\n", e->p.val.s, ITEM_RNBRACKET); goto error; } done: DBG("xl_parse_name: name [%.*s] index [%d]\n", e->p.val.len, e->p.val.s, e->p.ind); return p; error: return NULL; } char* xl_parse_svname(char *s, xl_spec_p e, int flags, trans_t **tr) { char *p; char *p0; int mode = 0; if(s==NULL || e==NULL || *s!=ITEM_MARKER) { LOG(L_ERR, "xl_parse_svname: error - bad parameters\n"); return NULL; } DBG("xl_parse_svname: parsing [%s]\n", s); p = s; p++; if(*p==ITEM_LNBRACKET) { mode = 1; p++; } if(p && (*p=='v' || *p=='V')) p++; else { LOG(L_ERR, "xl_parse_svname: error - bad name [%s]\n", s); goto error; } if(p==0) { LOG(L_ERR, "xl_parse_svname: error - bad name [%s]!\n", s); goto error; } if(*p==ITEM_LNBRACKET) p++; else { if((p[0]!='a' && p[0]!='A') || (p[1]!='r' && p[1]!='R') || (p[2]!=ITEM_LNBRACKET)) { LOG(L_ERR, "xl_parse_svname: error - bad name [%s/%s]!!\n", s, p); goto error; } p += 3; } e->p.val.s = p; while(p && *p!='\0' && *p!=ITEM_RNBRACKET) p++; if(p==0 || *p!=ITEM_RNBRACKET) { LOG(L_ERR, "xl_parse_svname: error - bad name [%s]!!!\n", s); goto error; } e->p.val.len = p - e->p.val.s; //p++; if(mode==1) { p++; while (*p && *p==' ') p++; if(*p==TR_LBRACKET) { p0 = parse_transformation(p, tr); if(p0==NULL) { LOG(L_ERR, "ERROR:xl_parse_svname: bad tr in pvar name " "\"%s\"\n", s); goto error; } p = p0; } while (*p && *p==' ') p++; if(*p!=ITEM_RNBRACKET) { LOG(L_ERR, "xl_parse_svname: error - bad name [%s]!!!!\n", s); goto error; } p--; } e->p.data = (void*)add_var(&e->p.val); if(e->p.data==NULL) { LOG(L_ERR, "xl_parse_svname: error - no more mem for [%s]\n", s); goto error; } e->itf = xl_get_script_var; e->type = XL_SCRIPTVAR; return p; error: memset(e, 0, sizeof(xl_spec_t)); return NULL; } char* xl_parse_vname(char *s, xl_spec_p e, int flags, trans_t **tr) { char *p; char *p0; int_str avp_name; int avp_type; int mode; int pmode; xl_spec_t e0; if(s==NULL || e==NULL || *s!=ITEM_MARKER) { LOG(L_ERR, "xl_parse_vname: error - bad parameters\n"); return NULL; } pmode = 0; p = s; #ifdef EXTRA_DEBUG DBG("xl_parse_vname: parsing [%s]\n", p); #endif p++; if(*p==ITEM_LNBRACKET) { pmode = 1; p++; } e->p.ind = 0; if(p[0]=='a' || p[0]=='A') { /* look for avp */ if(strlen(p)>6 && (p[1]=='v' || p[1]=='V') && (p[2]=='p' || p[2]=='P')) { /* long name */ if(p[3]==ITEM_LNBRACKET || ((p[3]=='t' || p[3]=='T') && p[4]==ITEM_LNBRACKET)) { mode = 1; if(p[3]==ITEM_LNBRACKET) p += 4; else p += 5; } else if((p[3]=='g' || p[3]=='G') && p[4]==ITEM_LNBRACKET) { mode = 2; p += 5; } else if((p[3]=='s' || p[3]=='S') && p[4]==ITEM_LNBRACKET) { mode = 3; p += 5; } else if((p[3]=='p' || p[3]=='P') && p[4]==ITEM_LNBRACKET) { mode = 4; p += 5; } else { LOG(L_ERR, "xl_parse_vname: error - bad pvar name (1) %s\n", p); return NULL; } } else if(strlen(p)>4 && (p[1]==ITEM_LNBRACKET || p[2]==ITEM_LNBRACKET)) { /* short name */ if(p[1]==ITEM_LNBRACKET || ((p[1]=='t' || p[1]=='T') && p[2]==ITEM_LNBRACKET)) { mode = 1; if(p[1]==ITEM_LNBRACKET) p += 2; else p += 3; } else if((p[1]=='g' || p[1]=='G') && p[2]==ITEM_LNBRACKET) { mode = 2; p += 3; } else if((p[1]=='s' || p[1]=='S') && p[2]==ITEM_LNBRACKET) { mode = 3; p += 3; } else if((p[1]=='p' || p[1]=='P') && p[2]==ITEM_LNBRACKET) { mode = 4; p += 3; } else { LOG(L_ERR, "xl_parse_vname: error - bad pvar name (2) %s\n", p); return NULL; } } else { LOG(L_ERR, "xl_parse_vname: error - bad pvar name (3) %s\n", p); return NULL; } } else if (p[0]=='h' || p[0]=='H') { /* look for hdr */ if(strlen(p)>6 && (p[1]=='d' || p[1]=='D') && (p[2]=='r' || p[2]=='R') && p[3]==ITEM_LNBRACKET) { mode = 10; p += 4; } else if(strlen(p)>4 && p[1]==ITEM_LNBRACKET) { mode = 10; p += 2; } else { LOG(L_ERR, "xl_parse_vname: error - bad pvar name (4) %s\n", p); return NULL; } } else { LOG(L_ERR, "xl_parse_vname: error - bad pvar name (5) %s\n", p); return NULL; } if(mode==10) { /* hdr - we expect a letter or $ */ if(*p==ITEM_MARKER) { /* pseudo var */ if(flags&XL_LEVEL2) { LOG(L_ERR, "xl_parse_xname: error - too many var levels" " [%s]!\n", p); goto error; } p = xl_parse_spec(p, &e0, flags|XL_LEVEL2); if(p==NULL) goto error; /* dynamic name */ e->dp.itf = e0.itf; e->flags |= e0.flags; memcpy(&(e->p), &(e0.p), sizeof(xl_param_t)); p = xl_parse_index(p, &(e->dp.ind)); if(p==NULL) goto error; e->flags |= XL_DPARAM; } else { /* name */ if(((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z'))) { LOG(L_ERR, "xl_parse_vname: error parsing hdr name" " [%s]!\n", p); goto error; } p = xl_parse_name(p, e); if(p==NULL) goto error; if(xl_update_hdrname(e)!=0) goto error; } e->itf = xl_get_header; e->type = XL_HDR; if(e->flags&XL_DPARAM) DBG("xl_parse_vname: hdr double reference (%p/%p) (%.*s)" " (%d) (%d/0x%X)\n", e->itf, e->dp.itf, (e->p.val.s)?e->p.val.len:0, (e->p.val.s)?e->p.val.s:"", e->p.val.len, e->p.ind, e->flags); goto done; } else { /* avp - we expect s:, i:, letter or $ */ if(*p==ITEM_MARKER) { /* pseudo var */ if(flags&XL_LEVEL2) { LOG(L_ERR, "xl_parse_vname: error - too many var levels" " [%s]!!\n", p); goto error; } p0 =p; p = xl_parse_spec(p, &e0, flags|XL_LEVEL2); if(p==NULL) goto error; if(e0.type!=XL_NULL && e0.itf!=NULL) { /* dynamic name */ e->dp.itf = e0.itf; e->flags |= e0.flags; memcpy(&(e->p), &(e0.p), sizeof(xl_param_t)); p0 = p; p = xl_parse_index(p, &(e->dp.ind)); if(p==NULL) goto error; e->flags |= XL_DPARAM; } else { LOG(L_ERR, "ERROR:xl_parse_vname: unknow pseudo-variable" "\"%s\"\n", p0); goto error; } } else { /* name or alias */ avp_type = 0; p = xl_parse_name(p, e); if(p==NULL) goto error; /* identify avp */ if(parse_avp_spec(&e->p.val, &avp_type, &avp_name)!=0) { LOG(L_ERR, "xl_parse_vname: error - bad avp name [%.*s]\n", e->p.val.len, e->p.val.s); goto error; } if(avp_type&AVP_NAME_STR) { DBG("xl_parse_vname: avp [s:%.*s]\n", avp_name.s.len, avp_name.s.s); e->p.val.s = avp_name.s.s; e->p.val.len = avp_name.s.len; } else { DBG("xl_parse_vname: avp [i:%d]\n", avp_name.n); e->p.val.s = NULL; e->p.val.len = avp_name.n; } e->flags |= (avp_type<<16); } e->itf = xl_get_avp; e->type = XL_AVP; if(e->flags&XL_DPARAM) DBG("xl_parse_vname: avp double reference (%p/%p) (%.*s)" " (%d) (%d/0x%d)\n", e->itf, e->dp.itf, (e->p.val.s)?e->p.val.len:0, (e->p.val.s)?e->p.val.s:"", e->p.val.len, e->p.ind, e->flags); goto done; } done: if(*p != ITEM_RNBRACKET) { LOG(L_ERR, "xl_parse_vname: error parsing format" " [%s] expecting '%c'!\n", s, ITEM_RNBRACKET); goto error; } if(e->p.ind!=0 && flags&XL_DISABLE_MULTI) { e->itf = NULL; if(flags&XL_THROW_ERROR) goto error; } if(pmode==1) { p++; while (*p && *p==' ') p++; if(*p==TR_LBRACKET) { p0 = parse_transformation(p, tr); if(p0==NULL) { LOG(L_ERR, "ERROR:xl_parse_vname: bad tr in pvar name " "\"%s\"\n", s); goto error; } p = p0; } while (*p && *p==' ') p++; if(*p!=ITEM_RNBRACKET) { LOG(L_ERR, "xl_parse_vname: error - bad name [%s]!!!!\n", s); goto error; } p--; } return p; error: return NULL; } /***** pseudo-variables table *****/ /** * { { name.s, name.len }, * { spec.type, spec.flags, spec.itf, * { { spec.p.val.s, spec.p.val.len }, spec.p.ind}, * { spec.dp.itf, spec.dp.ind } } } */ static struct _xl_table { str name; xl_spec_t spec; } _xl_names_table[] = { {{"ai", (sizeof("ai")-1)}, /* */ { XL_PAI_URI, 0, xl_get_pai, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ar", (sizeof("ar")-1)}, /* auth realm */ { XL_AUTH_REALM, 0, xl_get_authattr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"au", (sizeof("au")-1)}, /* */ { XL_AUTH_USERNAME, 0, xl_get_authattr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"Au", (sizeof("Au")-1)}, /* */ { XL_ACC_USERNAME, 0, xl_get_acc_username, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"bf", (sizeof("bf")-1)}, /* */ { XL_BFLAGS, 0, xl_get_bflags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"bF", (sizeof("bF")-1)}, /* */ { XL_HEXBFLAGS, 0, xl_get_hexbflags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"br", (sizeof("br")-1)}, /* */ { XL_BRANCH, 0, xl_get_branch, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"bR", (sizeof("bR")-1)}, /* */ { XL_BRANCHES, 0, xl_get_branches, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ci", (sizeof("ci")-1)}, /* */ { XL_CALLID, 0, xl_get_callid, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"cl", (sizeof("cl")-1)}, /* */ { XL_CONTENT_LENGTH, 0, xl_get_content_length, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"cs", (sizeof("cs")-1)}, /* */ { XL_CSEQ, 0, xl_get_cseq, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ct", (sizeof("ct")-1)}, /* */ { XL_CONTACT, 0, xl_get_contact, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"cT", (sizeof("cT")-1)}, /* */ { XL_CONTENT_TYPE, 0, xl_get_content_type, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"dd", (sizeof("dd")-1)}, /* */ { XL_DSTURI_DOMAIN, 0, xl_get_dsturi_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"di", (sizeof("di")-1)}, /* */ { XL_DIVERSION_URI, 0, xl_get_diversion, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"dp", (sizeof("dp")-1)}, /* */ { XL_DSTURI_PORT, 0, xl_get_dsturi_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"dP", (sizeof("dP")-1)}, /* */ { XL_DSTURI_PROTOCOL, 0, xl_get_dsturi_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"ds", (sizeof("ds")-1)}, /* */ { XL_DSET, 0, xl_get_dset, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"du", (sizeof("du")-1)}, /* */ { XL_DSTURI, 0, xl_get_dsturi, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"duri", (sizeof("duri")-1)}, /* */ { XL_DSTURI, 0, xl_get_dsturi, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"err.class", (sizeof("err.class")-1)}, /* */ { XL_ERR_CLASS, 0, xl_get_errinfo_attr, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"err.level", (sizeof("err.level")-1)}, /* */ { XL_ERR_LEVEL, 0, xl_get_errinfo_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"err.info", (sizeof("err.info")-1)}, /* */ { XL_ERR_INFO, 0, xl_get_errinfo_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"err.rcode", (sizeof("err.rcode")-1)}, /* */ { XL_ERR_RCODE, 0, xl_get_errinfo_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"err.rreason", (sizeof("err.rreason")-1)}, /* */ { XL_ERR_RREASON, 0, xl_get_errinfo_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"fd", (sizeof("fd")-1)}, /* */ { XL_FROM_DOMAIN, 0, xl_get_from_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"from.domain", (sizeof("from.domain")-1)}, /* */ { XL_FROM_DOMAIN, 0, xl_get_from_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"fn", (sizeof("fn")-1)}, /* */ { XL_FROM_DISPLAYNAME, 0, xl_get_from_attr, {{0, 5}, 0, 0}, {0, 0}, 0}}, {{"fs", (sizeof("fs")-1)}, /* */ { XL_FORCE_SOCK, 0, xl_get_force_sock, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ft", (sizeof("ft")-1)}, /* */ { XL_FROM_TAG, 0, xl_get_from_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"fu", (sizeof("fu")-1)}, /* */ { XL_FROM, 0, xl_get_from_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"from", (sizeof("from")-1)}, /* */ { XL_FROM, 0, xl_get_from_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"fU", (sizeof("fU")-1)}, /* */ { XL_FROM_USERNAME, 0, xl_get_from_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"from.user", (sizeof("from.user")-1)}, /* */ { XL_FROM_USERNAME, 0, xl_get_from_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"mb", (sizeof("mb")-1)}, /* */ { XL_MSG_BUF, 0, xl_get_msg_buf, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"mf", (sizeof("mf")-1)}, /* */ { XL_FLAGS, 0, xl_get_flags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"mF", (sizeof("mF")-1)}, /* */ { XL_HEXFLAGS, 0, xl_get_hexflags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"mi", (sizeof("mi")-1)}, /* */ { XL_MSGID, 0, xl_get_msgid, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ml", (sizeof("ml")-1)}, /* */ { XL_MSG_LEN, 0, xl_get_msg_len, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"od", (sizeof("od")-1)}, /* */ { XL_OURI_DOMAIN, 0, xl_get_ouri_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"op", (sizeof("op")-1)}, /* */ { XL_OURI_PORT, 0, xl_get_ouri_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"oP", (sizeof("oP")-1)}, /* */ { XL_OURI_PROTOCOL, 0, xl_get_ouri_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"ou", (sizeof("ou")-1)}, /* */ { XL_OURI, 0, xl_get_ouri, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ouri", (sizeof("ouri")-1)}, /* */ { XL_OURI, 0, xl_get_ouri, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"oU", (sizeof("oU")-1)}, /* */ { XL_OURI_USERNAME, 0, xl_get_ouri_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"pd", (sizeof("pd")-1)}, /* */ { XL_PPI_DOMAIN, 0, xl_get_ppi_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"pn", (sizeof("pn")-1)}, /* */ { XL_PPI_DISPLAYNAME, 0, xl_get_ppi_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"pu", (sizeof("pu")-1)}, /* */ { XL_PPI, 0, xl_get_ppi_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"pU", (sizeof("pU")-1)}, /* */ { XL_PPI_USERNAME, 0, xl_get_ppi_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"pp", (sizeof("pp")-1)}, /* */ { XL_PID, 0, xl_get_pid, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rb", (sizeof("rb")-1)}, /* */ { XL_MSG_BODY, 0, xl_get_msg_body, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rc", (sizeof("rc")-1)}, /* */ { XL_RETURN_CODE, 0, xl_get_return_code, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"retcode", (sizeof("retcode")-1)}, /* */ { XL_RETURN_CODE, 0, xl_get_return_code, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rd", (sizeof("rd")-1)}, /* */ { XL_RURI_DOMAIN, 0, xl_get_ruri_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"ruri.domain", (sizeof("ruri.domain")-1)}, /* */ { XL_RURI_DOMAIN, 0, xl_get_ruri_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"re", (sizeof("re")-1)}, /* */ { XL_RPID_URI, 0, xl_get_rpid, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rm", (sizeof("rm")-1)}, /* */ { XL_METHOD, 0, xl_get_method, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rp", (sizeof("rp")-1)}, /* */ { XL_RURI_PORT, 0, xl_get_ruri_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"rP", (sizeof("rP")-1)}, /* */ { XL_RURI_PROTOCOL, 0, xl_get_ruri_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"rr", (sizeof("rr")-1)}, /* */ { XL_REASON, 0, xl_get_reason, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rs", (sizeof("rs")-1)}, /* */ { XL_STATUS, 0, xl_get_status, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rt", (sizeof("rt")-1)}, /* */ { XL_REFER_TO, 0, xl_get_refer_to, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ru", (sizeof("ru")-1)}, /* */ { XL_RURI, 0, xl_get_ruri, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ruri", (sizeof("ruri")-1)}, /* */ { XL_RURI, 0, xl_get_ruri, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"rU", (sizeof("rU")-1)}, /* */ { XL_RURI_USERNAME, 0, xl_get_ruri_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"ruri.user", (sizeof("ruri.user")-1)}, /* */ { XL_RURI_USERNAME, 0, xl_get_ruri_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"Ri", (sizeof("Ri")-1)}, /* */ { XL_RCVIP, 0, xl_get_rcvip, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"Rp", (sizeof("Rp")-1)}, /* */ { XL_RCVPORT, 0, xl_get_rcvport, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"sf", (sizeof("sf")-1)}, /* */ { XL_SFLAGS, 0, xl_get_sflags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"sF", (sizeof("sF")-1)}, /* */ { XL_HEXSFLAGS, 0, xl_get_hexsflags, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"src_ip", (sizeof("src_ip")-1)}, /* */ { XL_SRCIP, 0, xl_get_srcip, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"si", (sizeof("si")-1)}, /* */ { XL_SRCIP, 0, xl_get_srcip, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"sp", (sizeof("sp")-1)}, /* */ { XL_SRCPORT, 0, xl_get_srcport, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"td", (sizeof("td")-1)}, /* */ { XL_TO_DOMAIN, 0, xl_get_to_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"to.domain", (sizeof("to.domain")-1)}, /* */ { XL_TO_DOMAIN, 0, xl_get_to_attr, {{0, 3}, 0, 0}, {0, 0}, 0}}, {{"tn", (sizeof("tn")-1)}, /* */ { XL_TO_DISPLAYNAME, 0, xl_get_to_attr, {{0, 5}, 0, 0}, {0, 0}, 0}}, {{"tt", (sizeof("tt")-1)}, /* */ { XL_TO_TAG, 0, xl_get_to_attr, {{0, 4}, 0, 0}, {0, 0}, 0}}, {{"tu", (sizeof("tu")-1)}, /* */ { XL_TO, 0, xl_get_to_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"to", (sizeof("to")-1)}, /* */ { XL_TO, 0, xl_get_to_attr, {{0, 1}, 0, 0}, {0, 0}, 0}}, {{"tU", (sizeof("tU")-1)}, /* */ { XL_TO_USERNAME, 0, xl_get_to_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"to.user", (sizeof("to.user")-1)}, /* */ { XL_TO_USERNAME, 0, xl_get_to_attr, {{0, 2}, 0, 0}, {0, 0}, 0}}, {{"Tf", (sizeof("tf")-1)}, /* */ { XL_TIMEF, 0, xl_get_timef, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"Ts", (sizeof("ts")-1)}, /* */ { XL_TIMES, 0, xl_get_times, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{"ua", (sizeof("ua")-1)}, /* */ { XL_USERAGENT, 0, xl_get_useragent, {{0, 0}, 0, 0}, {0, 0}, 0}}, {{0, 0}, { 0, 0, 0, {{0, 0}, 0, 0}, {0, 0}, 0}} }; int xl_lookup_spec_name(str *pvname, xl_spec_p e, int flags) { int i; if(pvname==0 || e==0) { LOG(L_ERR, "xl_lookup_spec_name: error - bad parameters\n"); return -1; } for(i=0; _xl_names_table[i].name.s!=0; i++) { if(_xl_names_table[i].name.len==pvname->len && memcmp(_xl_names_table[i].name.s, pvname->s, pvname->len)==0) { DBG("xl_lookup_spec_name: found [%.*s] [%d]\n", pvname->len, pvname->s, _xl_names_table[i].spec.type); memcpy(e, &_xl_names_table[i].spec, sizeof(xl_spec_t)); return 0; } } e->p.val = *pvname; e->itf = NULL; e->type = XL_ITEM_EXTRA; i = xl_fill_extra_spec(e); if(i<0) { LOG(L_ERR, "xl_lookup_spec_name: error - searching in extra items\n"); return -1; } if(i!=0) { LOG(L_ERR, "xl_lookup_spec_name: not found PV [%.*s]\n", pvname->len, pvname->s); return -1; } DBG("xl_lookup_spec_name: found [%.*s] in extra items\n", pvname->len, pvname->s); return 0; } char* xl_parse_spec(char *s, xl_spec_p e, int flags) { char *p, *p0; str pvname; int pvstate; int found; trans_t *tr; if(s==NULL || e==NULL || *s!=ITEM_MARKER) { LOG(L_ERR, "xl_parse_item: error - bad parameters\n"); return NULL; } tr = 0; pvstate = 0; found = 0; memset(e, 0, sizeof(xl_spec_t)); p = s; p++; if(*p==ITEM_LNBRACKET) { p++; pvstate = 1; } pvname.s = p; /* parse special pvar : marker, avp, hdr, colors */ switch(*p) { case ITEM_MARKER: e->itf = xl_get_marker; e->type = XL_MARKER; found = 1; break; case 'a': case 'A': if((p[1]==ITEM_LNBRACKET) || ((p[1]=='t'||p[1]=='T'||p[1]=='g'|| p[1]=='G' ||p[1]=='p'||p[1]=='P'||p[1]=='s'||p[1]=='S') &&(p[2]==ITEM_LNBRACKET)) || ((p[1]=='v' || p[1]=='V') &&(p[2]=='p' || p[2]=='P') &&((p[3]==ITEM_LNBRACKET) ||((p[3]=='t'||p[3]=='T'||p[3]=='g'||p[3]=='G' ||p[3]=='p'||p[3]=='P'||p[3]=='s'||p[3]=='s') &&(p[4]==ITEM_LNBRACKET)))) ) { p0 = xl_parse_vname((pvstate==1)?p-2:p-1, e, flags, &tr); if(p0==NULL) goto error; p = p0; e->type = XL_AVP; found = 1; } break; case 'C': p++; e->p.val.s = p; /* foreground */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': case 'S': case 'R': case 'G': case 'Y': case 'B': case 'P': case 'C': case 'W': break; default: goto extra_spec; } p++; /* background */ switch(*p) { case 'x': case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': break; default: goto extra_spec; } /* end */ if(flags&XL_DISABLE_COLORS) { e->itf = NULL; e->type = XL_NONE; if(flags&XL_THROW_ERROR) goto error; } else { e->p.val.len = 2; e->itf = xl_get_color; e->type = XL_COLOR; } found = 1; break; case 'h': case 'H': if((p[1]==ITEM_LNBRACKET) || ((p[1]=='d' || p[1]=='D') && (p[2]=='r' || p[2]=='R') && p[3]==ITEM_LNBRACKET)) { p0 = xl_parse_vname((pvstate==1)?p-2:p-1, e, flags, &tr); if(p0==NULL) goto error; p = p0; } else { goto extra_spec; } e->type = XL_HDR; found = 1; break; case 'v': case 'V': if((p[1]==ITEM_LNBRACKET) || ((p[1]=='a' || p[1]=='A') && (p[2]=='r' || p[2]=='R') && p[3]==ITEM_LNBRACKET)) { p0 = xl_parse_svname((pvstate==1)?p-2:p-1, e, flags, &tr); if(p0==NULL) goto error; p = p0; } else { goto extra_spec; } e->type = XL_SCRIPTVAR; found = 1; break; } if(found==1) { if(pvstate==1) { if(*(++p) == ITEM_RNBRACKET) goto next_spec; LOG(L_ERR, "ERROR:xl_parse_spec: bad pvar name at: " "\"%s\"\n", pvname.s); goto error; } goto next_spec; } extra_spec: /* look for invalid name char */ p = pvname.s; while(p && *p) { if((*p>='0' && *p<='9') || (*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p=='_') || (*p=='.')) { p++; } else { break; } } if(pvstate==1) { /* look for ')' '{' */ if(p && *p!=ITEM_RNBRACKET && *p!=TR_LBRACKET) { LOG(L_ERR, "ERROR:xl_parse_spec: bad pvar name " "\"%s\"\n", pvname.s); goto error; } pvname.len = p - pvname.s; /* look for '{' */ if(p && *p==TR_LBRACKET) { p0 = parse_transformation(p, &tr); if(p0==NULL) { LOG(L_ERR, "ERROR:xl_parse_spec: bad tr in pvar name " "\"%s\"\n", pvname.s); goto error; } p = p0; if(*p!=ITEM_RNBRACKET) { LOG(L_ERR, "ERROR:xl_parse_spec: bad pvar name " "\"%s\"!\n", pvname.s); goto error; } } } else { pvname.len = p - pvname.s; p--; /* skip the end again */ } /*DBG("xl_parse_spec: searching [%.*s]\n", pvname.len, pvname.s);*/ if(xl_lookup_spec_name(&pvname, e, flags)!=0) { LOG(L_ERR, "ERROR:xl_parse_spec: error searching pvar " "\"%.*s\"\n", pvname.len, pvname.s); goto error; } next_spec: e->trans = (void*)tr; if(*p != '\0') p++; return p; error: /* destroy trans */ if(tr!=0) free_transformation(tr); return NULL; } /** * */ int xl_parse_format(char *s, xl_elem_p *el, int flags) { char *p, *p0; int n = 0; xl_elem_p e, e0; if(s==NULL || el==NULL) return -1; DBG("xl_parse_format: parsing [%s]\n", s); p = s; *el = NULL; e = e0 = NULL; while(*p) { e0 = e; e = pkg_malloc(sizeof(xl_elem_t)); if(!e) goto error; memset(e, 0, sizeof(xl_elem_t)); n++; if(*el == NULL) *el = e; if(e0) e0->next = e; e->text.s = p; while(*p && *p!=ITEM_MARKER) p++; e->text.len = p - e->text.s; if(*p == '\0') break; p0 = xl_parse_spec(p, &e->spec, flags); if(p0==NULL) goto error; if(*p0 == '\0') break; p = p0; } DBG("xl_parse_format: format parsed OK: [%d] items\n", n); return 0; error: xl_elem_free_all(*el); *el = NULL; return -1; } int xl_get_spec_name(struct sip_msg* msg, xl_spec_p sp, xl_value_t *value, int flags) { if(msg==NULL || sp==NULL || sp->itf==NULL || value==NULL) return -1; memset(value, 0, sizeof(xl_value_t)); if(sp->flags&XL_DPARAM) { if(sp->dp.itf==NULL) { LOG(L_ERR, "xl_get_spec_name: error - null sp->dp.itf\n"); return -1; } if((*sp->dp.itf)(msg, value, &(sp->p), flags)!=0) { LOG(L_ERR, "xl_get_spec_name: error - cannot get the value\n"); return -1; } } else { if(sp->p.val.s!=NULL) { value->rs = sp->p.val; value->flags = XL_VAL_STR; } else { value->ri = sp->p.val.len; value->flags = XL_VAL_INT|XL_TYPE_INT; } } return 0; } int xl_get_avp_name(struct sip_msg* msg, xl_spec_p sp, int_str *avp_name, unsigned short *name_type) { xl_value_t xv; if(sp==NULL || avp_name==NULL || name_type==NULL) { LOG(L_ERR, "xl_get_avp_name: bad parameters\n"); return -1; } memset(avp_name, 0, sizeof(int_str)); *name_type = 0; if((sp->flags & XL_DPARAM)&&(sp->dp.itf!=0)) { memset(&xv, 0, sizeof(xl_value_t)); if((*sp->dp.itf)(msg, &xv, &(sp->p), 0)!=0) { LOG(L_ERR, "xl_get_avp_name: unable to get dynamic name\n"); return -1; } if(xv.flags&XL_NULL || xv.flags&XL_EMPTY) { LOG(L_ERR, "xl_get_avp_name: null or empty dynamic name\n"); return -1; } if((xv.flags&XL_TYPE_INT) && (xv.flags&XL_VAL_INT)) { avp_name->n = xv.ri; } else { avp_name->s = xv.rs; *name_type = AVP_NAME_STR; } } else { if(sp->p.val.s!=NULL) { *name_type = AVP_NAME_STR; avp_name->s = sp->p.val; } else { avp_name->n = sp->p.val.len; } } *name_type |= (sp->flags&0xffff0000)>>16; return 0; } int xl_get_spec_index(xl_spec_p sp, int *idx) { if(sp==NULL || idx==NULL) return -1; *idx = 0; if(sp->flags&XL_DPARAM) { *idx = sp->dp.ind; } else { *idx = sp->p.ind; } return 0; } int xl_get_spec_value(struct sip_msg* msg, xl_spec_p sp, xl_value_t *value, int flags) { xl_param_t tp; xl_value_t tv; int ret = 0; if(msg==NULL || sp==NULL || value==NULL) return -1; memset(value, 0, sizeof(xl_value_t)); if(sp->type==XL_NONE) return -1; if(sp->type==XL_ITEM_EXTRA && sp->itf==NULL) { if(xl_fill_extra_spec(sp)<0) { LOG(L_ERR, "xl_get_spec_value: error - filling extra spec\n"); return -1; } } if(sp->itf==NULL) { LOG(L_ERR, "xl_get_spec_value: error - null sp->itf\n"); return -1; } if(sp->flags&XL_DPARAM) { if(sp->dp.itf==NULL) { LOG(L_ERR, "xl_get_spec_value: error - null sp->dp.itf\n"); return -1; } memset(&tv, 0, sizeof(xl_value_t)); (*sp->dp.itf)(msg, &tv, &(sp->p), (flags|(sp->flags&0xffff0000))); if(tv.flags&XL_VAL_NULL) return xl_get_null(msg, value, &(sp->p), flags); memset(&tp, 0, sizeof(xl_param_t)); if((tv.flags&XL_TYPE_INT) && (tv.flags&XL_VAL_INT)) { tp.val.len = tv.ri; #ifdef EXTRA_DEBUG DBG("xl_get_spec_value: dynamic int name [%d]\n", tv.ri); #endif } else { tp.val = tv.rs; #ifdef EXTRA_DEBUG DBG("xl_get_spec_value: dynamic str name [%.*s]\n", tv.rs.len, tv.rs.s); #endif } tp.ind = sp->dp.ind; ret = (*sp->itf)(msg, value, &tp, flags); if(ret!=0) return ret; if(sp->trans) return run_transformations(msg, (trans_t*)sp->trans, value); return ret; } else { ret = (*sp->itf)(msg, value, &(sp->p), (flags|(sp->flags&0xffff0000))); if(ret!=0) return ret; if(sp->trans) return run_transformations(msg, (trans_t*)sp->trans, value); return ret; } } int xl_print_spec(struct sip_msg* msg, xl_spec_p sp, char *buf, int *len) { xl_value_t tok; if(msg==NULL || sp==NULL || buf==NULL || len==NULL) return -1; if(*len <= 0) return -1; memset(&tok, 0, sizeof(xl_value_t)); /* put the value of the specifier */ if(xl_get_spec_value(msg, sp, &tok, 0)==0) { if(tok.flags&XL_VAL_NULL) tok.rs = str_null; if(tok.rs.len < *len) memcpy(buf, tok.rs.s, tok.rs.len); else goto overflow; } *len = tok.rs.len; buf[tok.rs.len] = '\0'; return 0; overflow: LOG(L_ERR, "xl_print_spec: buffer overflow -- increase the buffer size...\n"); return -1; } int xl_printf(struct sip_msg* msg, xl_elem_p list, char *buf, int *len) { int n, h; xl_value_t tok; xl_elem_p it; char *cur; if(msg==NULL || list==NULL || buf==NULL || len==NULL) return -1; if(*len <= 0) return -1; *buf = '\0'; cur = buf; h = 0; n = 0; for (it=list; it; it=it->next) { /* put the text */ if(it->text.s && it->text.len>0) { if(n+it->text.len < *len) { memcpy(cur, it->text.s, it->text.len); n += it->text.len; cur += it->text.len; } else { LOG(L_ERR, "xl_printf: no more space for text [%d]\n", it->text.len); goto overflow; } } /* put the value of the specifier */ if(it->spec.type!=XL_NONE && xl_get_spec_value(msg, &(it->spec), &tok, 0)==0) { if(tok.flags&XL_VAL_NULL) tok.rs = str_null; if(n+tok.rs.len < *len) { if(tok.rs.len>0) { memcpy(cur, tok.rs.s, tok.rs.len); n += tok.rs.len; cur += tok.rs.len; } /* check for color entries to reset later */ if (*it->spec.itf == xl_get_color) h = 1; } else { LOG(L_ERR, "xl_printf: no more space for spec value\n"); goto overflow; } } } /* reset to default after entry */ if (h == 1) { h = sizeof("\033[0m")-1; if (n+h < *len) { memcpy(cur, "\033[0m", h); n += h; cur += h; } else { LOG(L_ERR, "xl_printf: no more space for color spec\n"); goto overflow; } } goto done; overflow: LOG(L_ERR, "xl_printf: buffer overflow -- increase the buffer size...\n"); return -1; done: #ifdef EXTRA_DEBUG DBG("xl_printf: final buffer length %d\n", n); #endif *cur = '\0'; *len = n; return 0; } int xl_elem_free_all(xl_elem_p log) { xl_elem_p t; while(log) { t = log; log = log->next; pkg_free(t); } return 0; } itemname_list_t* parse_itemname_list(char *s, unsigned int type) { itemname_list_t* head = NULL; itemname_list_t* al = NULL; itemname_list_t* last = NULL; char *p; xl_spec_t spec; if(s==NULL) { LOG(L_ERR, "parse_itemname_list: error - bad parameters\n"); return NULL; } p = s; while(*p) { while(*p && (*p==' '||*p=='\t'||*p==','||*p==';')) p++; if(*p=='\0') { if(head==NULL) LOG(L_ERR, "parse_itemname_list: error - wrong item name list [%s]\n", s); return head; } p = xl_parse_spec(p, &spec, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS); if(p==NULL || (type && spec.type!=type)) { LOG(L_ERR, "parse_itemname_list: error - wrong item name list [%s]!\n", s); goto error; } al = (itemname_list_t*)pkg_malloc(sizeof(itemname_list_t)); if(al==NULL) { LOG(L_ERR, "parse_itemname_list: error - no more memory!\n"); goto error; } memset(al, 0, sizeof(itemname_list_t)); memcpy(&al->sname, &spec, sizeof(xl_spec_t)); if(last==NULL) { head = al; last = al; } else { last->next = al; last = al; } } return head; error: while(head) { al = head; head=head->next; pkg_free(al); } return NULL; } void xl_value_destroy(xl_value_t *val) { if(val==0) return; if(val->flags&XL_VAL_PKG) pkg_free(val->rs.s); if(val->flags&XL_VAL_SHM) shm_free(val->rs.s); memset(val, 0, sizeof(xl_value_t)); } void xl_spec_free(xl_spec_t *spec) { if(spec==0) return; pkg_free(spec); }