/* * $Id: avpops_impl.c 1563 2007-02-02 15:32:27Z miconda $ * * Copyright (C) 2004-2006 Voice Sistem SRL * * This file is part of Open SIP Express Router (openser). * * 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-04 first version (ramona) * 2005-01-30 "fm" (fast match) operator added (ramona) * 2005-01-30 avp_copy (copy/move operation) added (ramona) */ #include #include #include #include #include #include "../../ut.h" #include "../../dprint.h" #include "../../usr_avp.h" #include "../../action.h" #include "../../ip_addr.h" #include "../../config.h" #include "../../dset.h" #include "../../data_lump.h" #include "../../data_lump_rpl.h" #include "../../items.h" #include "../../parser/parse_from.h" #include "../../parser/parse_uri.h" #include "../../mem/mem.h" #include "avpops_impl.h" #include "avpops_db.h" #define avpops_str2int_str(a, b) \ do { \ if(a.s==0) \ b.n = a.len; \ else \ b.s = a; \ } while(0) static db_key_t store_keys[6]; static db_val_t store_vals[6]; static str empty={"",0}; #define AVP_PRINTBUF_SIZE 1024 static char printbuf[AVP_PRINTBUF_SIZE]; void init_store_avps( char **db_columns) { /* unique user id */ store_keys[0] = db_columns[0]; /*uuid*/ store_vals[0].type = DB_STR; store_vals[0].nul = 0; /* attribute */ store_keys[1] = db_columns[1]; /*attribute*/ store_vals[1].type = DB_STR; store_vals[1].nul = 0; /* value */ store_keys[2] = db_columns[2]; /*value*/ store_vals[2].type = DB_STR; store_vals[2].nul = 0; /* type */ store_keys[3] = db_columns[3]; /*type*/ store_vals[3].type = DB_INT; store_vals[3].nul = 0; /* user name */ store_keys[4] = db_columns[4]; /*username*/ store_vals[4].type = DB_STR; store_vals[4].nul = 0; /* domain */ store_keys[5] = db_columns[5]; /*domain*/ store_vals[5].type = DB_STR; store_vals[5].nul = 0; } /* value 0 - attr value * value 1 - attr name * value 2 - attr type */ static int dbrow2avp(struct db_row *row, struct db_param *dbp, int_str attr, int just_val_flags) { unsigned int uint; int db_flags; str atmp; str vtmp; int_str avp_attr; int_str avp_val; int flags; flags = dbp->a.opd; if (just_val_flags==-1) { /* check for null fields into the row */ if (row->values[0].nul || row->values[1].nul || row->values[2].nul ) { LOG( L_ERR, "ERROR:avpops:dbrow2avp: dbrow contains NULL fields\n"); return -1; } /* check the value types */ if ( (row->values[0].type!=DB_STRING && row->values[0].type!=DB_STR) || (row->values[1].type!=DB_STRING && row->values[1].type!=DB_STR) || row->values[2].type!=DB_INT ) { LOG(L_ERR,"ERROR:avpops:dbrow2avp: wrong field types in dbrow\n"); return -1; } /* check the content of flag field */ uint = (unsigned int)row->values[2].val.int_val; db_flags = ((uint&AVPOPS_DB_NAME_INT)?0:AVP_NAME_STR) | ((uint&AVPOPS_DB_VAL_INT)?0:AVP_VAL_STR); DBG("db_flags=%d, flags=%d\n",db_flags,flags); /* does the avp type match ? */ if(!((flags&(AVPOPS_VAL_INT|AVPOPS_VAL_STR))==0 || ((flags&AVPOPS_VAL_INT)&&((db_flags&AVP_NAME_STR)==0)) || ((flags&AVPOPS_VAL_STR)&&(db_flags&AVP_NAME_STR)))) return -2; } else { /* check the validity of value column */ if (row->values[0].nul || (row->values[0].type!=DB_STRING && row->values[0].type!=DB_STR && row->values[0].type!=DB_INT) ) { LOG(L_ERR,"ERROR:avpops:dbrow2avp: empty or wrong type for" " 'value' using scheme\n"); return -1; } db_flags = just_val_flags; } /* is the avp name already known? */ if ( (flags&AVPOPS_VAL_NONE)==0 ) { /* use the name */ avp_attr = attr; } else { /* take the name from db response */ if (row->values[1].type==DB_STRING) { atmp.s = (char*)row->values[1].val.string_val; atmp.len = strlen(atmp.s); } else { atmp = row->values[1].val.str_val; } if (db_flags&AVP_NAME_STR) { /* name is string */ avp_attr.s = atmp; } else { /* name is ID */ if (str2int( &atmp, &uint)==-1) { LOG(L_ERR,"ERROR:avpops:dbrow2avp: name is not ID as " "flags say <%s>\n", atmp.s); return -1; } avp_attr.n = (int)uint; } } /* now get the value as correct type */ if (row->values[0].type==DB_STRING) { vtmp.s = (char*)row->values[0].val.string_val; vtmp.len = strlen(vtmp.s); } else if (row->values[0].type==DB_STR){ vtmp = row->values[0].val.str_val; } else { vtmp.s = 0; vtmp.len = 0; } if (db_flags&AVP_VAL_STR) { /* value must be saved as string */ if (row->values[0].type==DB_INT) { vtmp.s = int2str( (unsigned long)row->values[0].val.int_val, &vtmp.len); } avp_val.s = vtmp; } else { /* value must be saved as integer */ if (row->values[0].type!=DB_INT) { if (vtmp.len==0 || vtmp.s==0 || str2int(&vtmp, &uint)==-1) { LOG(L_ERR,"ERROR:avpops:dbrow2avp: value is not int " "as flags say <%s>\n", vtmp.s); return -1; } avp_val.n = (int)uint; } else { avp_val.n = row->values[0].val.int_val; } } /* added the avp */ db_flags |= AVP_IS_IN_DB; /* set script flags */ db_flags |= (dbp->a.sval.flags>>16)&0xff00; return add_avp( (unsigned short)db_flags, avp_attr, avp_val); } inline static str* get_source_uri(struct sip_msg* msg,int source) { /* which uri will be used? */ if (source&AVPOPS_USE_FROM) { /* from */ if (parse_from_header( msg )<0 ) { LOG(L_ERR,"ERROR:avpops:get_source_uri: failed " "to parse from\n"); goto error; } return &(get_from(msg)->uri); } else if (source&AVPOPS_USE_TO) { /* to */ if (parse_headers( msg, HDR_TO_F, 0)<0) { LOG(L_ERR,"ERROR:avpops:get_source_uri: failed " "to parse to\n"); goto error; } return &(get_to(msg)->uri); } else if (source&AVPOPS_USE_RURI) { /* RURI */ if(msg->new_uri.s!=NULL && msg->new_uri.len>0) return &(msg->new_uri); return &(msg->first_line.u.request.uri); } else { LOG(L_CRIT,"BUG:avpops:get_source_uri: unknow source <%d>\n", source); goto error; } error: return 0; } static inline void int_str2db_val( int_str is_val, str *val, int is_s) { if (is_s) { /* val is string */ *val = is_val.s; } else { /* val is integer */ val->s = int2str((unsigned long)is_val.n, &val->len); } } static int avpops_get_aname(struct sip_msg* msg, struct fis_param *ap, int_str *avp_name, unsigned short *name_type) { if(ap==NULL || avp_name==NULL || name_type==NULL) { LOG(L_ERR, "avpops:avpops_get_aname: bad parameters\n"); return -1; } return xl_get_avp_name(msg, &ap->sval, avp_name, name_type); } #define AVPOPS_ATTR_LEN 64 static char avpops_attr_buf[AVPOPS_ATTR_LEN]; int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, struct db_param *dbp, int use_domain) { struct sip_uri uri; db_res_t *res = NULL; str uuid; int i, n, sh_flg; str *s0, *s1, *s2; int_str avp_name; xl_value_t xvalue; s0 = s1 = s2 = NULL; if (!((sp->opd&AVPOPS_VAL_PVAR)||(sp->opd&AVPOPS_VAL_STR))) { LOG(L_CRIT,"BUG:avpops:load_avps: invalid flag combination (%d/%d)\n", sp->opd, sp->ops); goto error; } /* get uuid from avp */ if (sp->opd&AVPOPS_VAL_PVAR) { if(xl_get_spec_value(msg, &(sp->sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:load_avps: error getting PVAR value (%d/%d)\n", sp->opd, sp->ops); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_ERR, "ERROR:avpops:load_avps: no value for first param\n"); goto error; } uuid = xvalue.rs; } else { uuid.s = sp->sval.p.val.s; uuid.len = sp->sval.p.val.len; } if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; } else { /* parse uri */ if (parse_uri(uuid.s, uuid.len, &uri)<0) { LOG(L_ERR,"ERROR:avpops:load_avps: failed to parse uri\n"); goto error; } /* check uri */ if(!uri.user.s|| !uri.user.len|| !uri.host.len|| !uri.host.s) { LOG(L_ERR,"ERROR:avpops:load_avps: incomplet uri <%.*s>\n", uuid.len, uuid.s); goto error; } if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_USER0)) s1 = &uri.user; if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_DOMAIN0)) s2 = &uri.host; } /* is dynamic avp name ? */ if(dbp->a.sval.flags&XL_DPARAM) { if(xl_get_spec_name(msg, &(dbp->a.sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:load_avps: error getting value for P2\n"); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_INFO, "INFO:avpops:load_avps: no value for p2\n"); goto error; } if(xvalue.flags&XL_VAL_STR) { if(xvalue.rs.len>=AVPOPS_ATTR_LEN) { LOG(L_ERR, "ERROR:avpops:load_avps: name too long [%d/%.*s...]\n", xvalue.rs.len, 16, xvalue.rs.s); goto error; } dbp->sa.s = avpops_attr_buf; memcpy(dbp->sa.s, xvalue.rs.s, xvalue.rs.len); dbp->sa.len = xvalue.rs.len; dbp->sa.s[dbp->sa.len] = '\0'; } else { LOG(L_INFO, "INFO:avpops:load_avps: no string value for p2\n"); goto error; } } /* do DB query */ res = db_load_avp( s0, s1, ((use_domain)||(sp->opd&AVPOPS_FLAG_DOMAIN0))?s2:0, dbp->sa.s, dbp->table, dbp->scheme); /* res query ? */ if (res==0) { LOG(L_ERR,"ERROR:avpops:load_avps: db_load failed\n"); goto error; } sh_flg = (dbp->scheme)?dbp->scheme->db_flags:-1; /* process the results */ for( n=0,i=0 ; in ; i++) { /* validate row */ memset(&avp_name, 0, sizeof(int_str)); if(dbp->a.sval.flags&XL_DPARAM) { if(xvalue.flags&XL_TYPE_INT) { avp_name.n = xvalue.ri; } else { avpops_str2int_str(xvalue.rs, avp_name); } } else { avpops_str2int_str(dbp->a.sval.p.val, avp_name); } //if ( dbrow2avp( &res->rows[i], dbp->a.opd, avp_name, sh_flg) < 0 ) if ( dbrow2avp( &res->rows[i], dbp, avp_name, sh_flg) < 0 ) continue; n++; } db_close_query( res ); DBG("DEBUG:avpops:load_avps: loaded avps = %d\n",n); return n?1:-1; error: return -1; } int ops_dbdelete_avps (struct sip_msg* msg, struct fis_param *sp, struct db_param *dbp, int use_domain) { struct sip_uri uri; int res; str uuid; xl_value_t xvalue; str *s0, *s1, *s2; s0 = s1 = s2 = NULL; if (!((sp->opd&AVPOPS_VAL_PVAR)||(sp->opd&AVPOPS_VAL_STR))) { LOG(L_CRIT, "BUG:avpops:dbdelete_avps: invalid flag combination (%d/%d)\n", sp->opd, sp->ops); goto error; } /* get uuid from avp */ if (sp->opd&AVPOPS_VAL_PVAR) { if(xl_get_spec_value(msg, &(sp->sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:dbdelete_avps: error getting PVAR value (%d/%d)\n", sp->opd, sp->ops); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_ERR, "ERROR:avpops:dbdelete_avps: no value for first param\n"); goto error; } uuid = xvalue.rs; } else { uuid.s = sp->sval.p.val.s; uuid.len = sp->sval.p.val.len; } if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; } else { /* parse uri */ if (parse_uri(uuid.s, uuid.len, &uri)<0) { LOG(L_ERR,"ERROR:avpops:dbdelete_avps: failed to parse uri\n"); goto error; } /* check uri */ if(!uri.user.s|| !uri.user.len|| !uri.host.len|| !uri.host.s) { LOG(L_ERR,"ERROR:avpops:dbdelete_avps: incomplet uri <%.*s>\n", uuid.len, uuid.s); goto error; } if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_USER0)) s1 = &uri.user; if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_DOMAIN0)) s2 = &uri.host; } /* is dynamic avp name ? */ if(dbp->a.sval.flags&XL_DPARAM) { if(xl_get_spec_name(msg, &(dbp->a.sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:dbdelete_avps: error getting value for P2\n"); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_INFO, "INFO:avpops:dbdelete_avps: no value for p2\n"); goto error; } if(xvalue.flags&XL_VAL_STR) { if(xvalue.rs.len>=AVPOPS_ATTR_LEN) { LOG(L_ERR, "ERROR:avpops:dbdelete_avps: name too long [%d/%.*s...]\n", xvalue.rs.len, 16, xvalue.rs.s); goto error; } dbp->sa.s = avpops_attr_buf; memcpy(dbp->sa.s, xvalue.rs.s, xvalue.rs.len); dbp->sa.len = xvalue.rs.len; dbp->sa.s[dbp->sa.len] = '\0'; } else { LOG(L_INFO, "INFO:avpops:dbdelete_avps: no string value for p2\n"); goto error; } } /* do DB delete */ res = db_delete_avp(s0, s1, (use_domain||(sp->opd&AVPOPS_FLAG_DOMAIN0))?s2:0, dbp->sa.s, dbp->table); /* res ? */ if (res<0) { LOG(L_ERR,"ERROR:avpops:dbdelete_avps: db_delete failed\n"); goto error; } return 1; error: return -1; } int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp, struct db_param *dbp, int use_domain) { struct sip_uri uri; struct usr_avp **avp_list; struct usr_avp *avp; unsigned short name_type; int_str avp_name; int_str i_s; str uuid; int keys_nr; int n; xl_value_t xvalue; str *s0, *s1, *s2; str *sn; s0 = s1 = s2 = NULL; name_type = 0; if (!((sp->opd&AVPOPS_VAL_PVAR)||(sp->opd&AVPOPS_VAL_STR))) { LOG(L_CRIT, "BUG:avpops:dbstore_avps: invalid flag combination (%d/%d)\n", sp->opd, sp->ops); goto error; } keys_nr = 6; /* uuid, avp name, avp val, avp type, user, domain */ /* get uuid from avp */ if (sp->opd&AVPOPS_VAL_PVAR) { if(xl_get_spec_value(msg, &(sp->sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:dbstore_avps: error getting PVAR value (%d/%d)\n", sp->opd, sp->ops); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_ERR, "ERROR:avpops:dbstore_avps: no value for first param\n"); goto error; } uuid = xvalue.rs; } else { uuid.s = sp->sval.p.val.s; uuid.len = sp->sval.p.val.len; } if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; } else { /* parse uri */ if (parse_uri(uuid.s, uuid.len, &uri)<0) { LOG(L_ERR,"ERROR:avpops:dbstore_avps: failed to parse uri\n"); goto error; } /* check uri */ if(!uri.user.s|| !uri.user.len|| !uri.host.len|| !uri.host.s) { LOG(L_ERR,"ERROR:avpops:dbstore_avps: incomplet uri <%.*s>\n", uuid.len, uuid.s); goto error; } if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_USER0)) s1 = &uri.user; if((sp->opd&AVPOPS_FLAG_URI0)||(sp->opd&AVPOPS_FLAG_DOMAIN0)) s2 = &uri.host; } /* set values for keys */ store_vals[0].val.str_val = (s0)?*s0:empty; store_vals[4].val.str_val = (s1)?*s1:empty; if (use_domain || sp->opd&AVPOPS_FLAG_DOMAIN0) store_vals[5].val.str_val = (s2)?*s2:empty; /* is dynamic avp name ? */ if(dbp->a.sval.flags&XL_DPARAM) { if(xl_get_spec_name(msg, &(dbp->a.sval), &xvalue, 0)!=0) { LOG(L_CRIT, "BUG:avpops:dbstore_avps: error getting value for P2\n"); goto error; } if(xvalue.flags&(XL_VAL_NULL|XL_VAL_EMPTY)) { LOG(L_INFO, "INFO:dbstore_avps: no value for P2\n"); goto error; } if(xvalue.flags&XL_TYPE_INT) { name_type = 0; avp_name.n = xvalue.ri; } else { name_type = AVP_NAME_STR; } if(xvalue.flags&XL_VAL_STR) { if(xvalue.rs.len>=AVPOPS_ATTR_LEN) { LOG(L_ERR, "ERROR:avpops:dbstore_avps: name too long [%d/%.*s...]\n", xvalue.rs.len, 16, xvalue.rs.s); goto error; } dbp->sa.s = avpops_attr_buf; memcpy(dbp->sa.s, xvalue.rs.s, xvalue.rs.len); dbp->sa.len = xvalue.rs.len; dbp->sa.s[dbp->sa.len] = '\0'; avp_name.s = dbp->sa; } else { LOG(L_INFO, "INFO:avpops:dbstore_avps: no string value for p2\n"); goto error; } } else if((dbp->a.opd&AVPOPS_VAL_NONE)==0) { name_type = (((dbp->a.opd&AVPOPS_VAL_INT))?0:AVP_NAME_STR); if(dbp->a.opd&AVPOPS_VAL_INT) { avp_name.n = dbp->a.sval.p.val.len; } else { avp_name.s = dbp->a.sval.p.val; } } /* set the script flags */ name_type |= ((dbp->a.sval.flags>>16)&0xff00); /* set uuid/(username and domain) fields */ n =0 ; if ((dbp->a.opd&AVPOPS_VAL_NONE)==0) { /* avp name is known ->set it and its type */ store_vals[1].val.str_val = dbp->sa; /*attr name*/ avp = search_first_avp( name_type, avp_name, &i_s, 0); for( ; avp; avp=search_first_avp( name_type, avp_name, &i_s, avp)) { /* don't insert avps which were loaded */ if (avp->flags&AVP_IS_IN_DB) continue; /* set type */ store_vals[3].val.int_val = (avp->flags&AVP_NAME_STR?0:AVPOPS_DB_NAME_INT)| (avp->flags&AVP_VAL_STR?0:AVPOPS_DB_VAL_INT); /* set value */ int_str2db_val( i_s, &store_vals[2].val.str_val, avp->flags&AVP_VAL_STR); /* save avp */ if (db_store_avp( store_keys, store_vals, keys_nr, dbp->table)==0 ) { avp->flags |= AVP_IS_IN_DB; n++; } } } else { /* avp name is unknown -> go through all list */ avp_list = get_avp_list(); avp = *avp_list; for ( ; avp ; avp=avp->next ) { /* don't insert avps which were loaded */ if (avp->flags&AVP_IS_IN_DB) continue; /* check if type match */ if ( !( (dbp->a.opd&(AVPOPS_VAL_INT|AVPOPS_VAL_STR))==0 || ((dbp->a.opd&AVPOPS_VAL_INT)&&((avp->flags&AVP_NAME_STR))==0) ||((dbp->a.opd&AVPOPS_VAL_STR)&&(avp->flags&AVP_NAME_STR)))) continue; /* set attribute name and type */ if ( (sn=get_avp_name(avp))==0 ) i_s.n = avp->id; else i_s.s = *sn; int_str2db_val( i_s, &store_vals[1].val.str_val, avp->flags&AVP_NAME_STR); store_vals[3].val.int_val = (avp->flags&AVP_NAME_STR?0:AVPOPS_DB_NAME_INT)| (avp->flags&AVP_VAL_STR?0:AVPOPS_DB_VAL_INT); /* set avp value */ get_avp_val( avp, &i_s); int_str2db_val( i_s, &store_vals[2].val.str_val, avp->flags&AVP_VAL_STR); /* save avp */ if (db_store_avp( store_keys, store_vals, keys_nr, dbp->table)==0) { avp->flags |= AVP_IS_IN_DB; n++; } } } DBG("DEBUG:avpops:dbstore_avps: %d avps were stored\n",n); return n==0?-1:1; error: return -1; } int ops_dbquery_avps(struct sip_msg* msg, xl_elem_t* query, itemname_list_t* dest) { int printbuf_len; if(msg==NULL || query==NULL) { LOG(L_ERR,"ERROR:avpops:ops_dbquery_avps: bad parameters\n"); return -1; } printbuf_len = AVP_PRINTBUF_SIZE-1; if(xl_printf(msg, query, printbuf, &printbuf_len)<0 || printbuf_len<=0) { LOG(L_ERR,"avpops:ops_dbquery_avps: error - cannot print the query\n"); return -1; } DBG("avpops:ops_dbquery_avps: query [%s]\n", printbuf); if(db_query_avp(msg, printbuf, dest)!=0) return -1; return 1; } int ops_delete_avp(struct sip_msg* msg, struct fis_param *ap) { struct usr_avp **avp_list; struct usr_avp *avp; struct usr_avp *avp_next; unsigned short name_type; int_str avp_name; int n; n = 0; if ( (ap->opd&AVPOPS_VAL_NONE)==0) { /* avp name is known ->search by name */ /* get avp name */ if(avpops_get_aname(msg, ap, &avp_name, &name_type)!=0) { LOG(L_ERR, "avpops:delete_avp: error getting dst AVP name\n"); return -1; } n = destroy_avps( name_type, avp_name, ap->ops&AVPOPS_FLAG_ALL ); } else { /* avp name is not given - we have just flags */ /* -> go through all list */ avp_list = get_avp_list(); avp = *avp_list; for ( ; avp ; avp=avp_next ) { avp_next = avp->next; /* check if type match */ if ( !( (ap->opd&(AVPOPS_VAL_INT|AVPOPS_VAL_STR))==0 || ((ap->opd&AVPOPS_VAL_INT)&&((avp->flags&AVP_NAME_STR))==0) || ((ap->opd&AVPOPS_VAL_STR)&&(avp->flags&AVP_NAME_STR)) ) ) continue; if(((ap->sval.flags>>16)&AVP_SCRIPT_MASK)!=0 && (((ap->sval.flags>>16)&AVP_SCRIPT_MASK)&avp->flags)==0) continue; /* remove avp */ destroy_avp( avp ); n++; if ( !(ap->ops&AVPOPS_FLAG_ALL) ) break; } } DBG("DEBUG:avpops:delete_avps: %d avps were removed\n",n); return n?1:-1; } int ops_copy_avp( struct sip_msg* msg, struct fis_param* src, struct fis_param* dst) { struct usr_avp *avp; struct usr_avp *prev_avp; int_str avp_val; int_str avp_val2; unsigned short name_type1; unsigned short name_type2; int_str avp_name1; int_str avp_name2; int n; n = 0; prev_avp = 0; /* get avp src name */ if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0) { LOG(L_ERR, "avpops:copy_avp: error getting src AVP name\n"); goto error; } /* get avp dst name */ if(avpops_get_aname(msg, dst, &avp_name2, &name_type2)!=0) { LOG(L_ERR, "avpops:copy_avp: error getting dst AVP name\n"); goto error; } avp = search_first_avp( name_type1, avp_name1, &avp_val, 0); while ( avp ) { /* build a new avp with new name, but old value */ /* do we need cast conversion ?!?! */ if((avp->flags&AVP_VAL_STR) && (dst->ops&AVPOPS_FLAG_CASTN)) { if(str2int(&avp_val.s, (unsigned int*)&avp_val2.n)!=0) { LOG(L_ERR,"ERROR:avpops:copy_avp: cannot convert str to int\n"); goto error; } if ( add_avp( name_type2, avp_name2, avp_val2)==-1 ) { LOG(L_ERR,"ERROR:avpops:copy_avp: failed to create new avp!\n"); goto error; } } else if(!(avp->flags&AVP_VAL_STR)&&(dst->ops&AVPOPS_FLAG_CASTS)) { avp_val2.s.s = int2str(avp_val.n, &avp_val2.s.len); if ( add_avp( name_type2|AVP_VAL_STR, avp_name2, avp_val2)==-1 ) { LOG(L_ERR,"ERROR:avpops:copy_avp: failed to create new avp.\n"); goto error; } } else { if ( add_avp( name_type2|(avp->flags&AVP_VAL_STR), avp_name2, avp_val)==-1 ) { LOG(L_ERR,"ERROR:avpops:copy_avp: failed to create new avp\n"); goto error; } } n++; /* copy all avps? */ if ( !(dst->ops&AVPOPS_FLAG_ALL) ) { /* delete the old one? */ if (dst->ops&AVPOPS_FLAG_DELETE) destroy_avp( avp ); break; } else { prev_avp = avp; avp = search_first_avp( name_type1, avp_name1, &avp_val, prev_avp); /* delete the old one? */ if (dst->ops&AVPOPS_FLAG_DELETE) destroy_avp( prev_avp ); } } return n?1:-1; error: return -1; } #define STR_BUF_SIZE 1024 static char str_buf[STR_BUF_SIZE]; inline static int append_0(str *in, str *out) { if (in->len+1>STR_BUF_SIZE) return -1; memcpy( str_buf, in->s, in->len); str_buf[in->len] = 0; out->len = in->len; out->s = str_buf; return 0; } int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst, struct fis_param* src) { struct action act; struct usr_avp *avp; unsigned short name_type; int_str avp_val; int_str avp_name; str val; int act_type; int n; int flags; xl_value_t xvalue; avp = NULL; flags = 0; if(src->sval.type==XL_AVP) { /* search for the avp */ if(avpops_get_aname(msg, src, &avp_name, &name_type)!=0) { LOG(L_ERR, "avpops:pushto_avp: error getting src AVP name\n"); goto error; } avp = search_first_avp( name_type, avp_name, &avp_val, 0); if (avp==0) { DBG("DEBUG:avpops:pushto_avp: no src avp found\n"); goto error; } flags = avp->flags; } else { if(xl_get_spec_value(msg, &(src->sval), &xvalue, 0)!=0) { LOG(L_ERR,"ERROR:avpops:pushto_avp: cannot get src value\n"); goto error; } if(xvalue.flags&XL_TYPE_INT) { avp_val.n = xvalue.ri; } else { flags = AVP_VAL_STR; avp_val.s = xvalue.rs; } } n = 0; do { /* the avp val will be used all the time as str */ if (flags&AVP_VAL_STR) { val = avp_val.s; } else { val.s = int2str((unsigned long)avp_val.n, &val.len); } act_type = 0; /* push the value into right position */ if (dst->opd&AVPOPS_USE_RURI) { if (dst->opd&AVPOPS_FLAG_USER0) act_type = SET_USER_T; else if (dst->opd&AVPOPS_FLAG_DOMAIN0) act_type = SET_HOST_T; else act_type = SET_URI_T; if ( flags&AVP_VAL_STR && append_0( &val, &val)!=0 ) { LOG(L_ERR,"ERROR:avpops:pushto_avp: failed to make 0 term.\n"); goto error; } } else if (dst->opd&AVPOPS_USE_DURI) { if (!(flags&AVP_VAL_STR)) { goto error; } } else if (dst->opd&AVPOPS_USE_BRANCH) { if (!(flags&AVP_VAL_STR)) { goto error; } } else { LOG(L_CRIT,"BUG:avpops:pushto_avp: destination unknown (%d/%d)\n", dst->opd, dst->ops); goto error; } if ( act_type ) { /* rewrite part of ruri */ if (n) { /* if is not the first modification, push the current uri as * branch */ if (append_branch( msg, 0, 0, 0, Q_UNSPECIFIED, 0, 0)!=1 ) { LOG(L_ERR,"ERROR:avpops:pushto_avp: append_branch action" " failed\n"); goto error; } } memset(&act, 0, sizeof(act)); act.elem[0].type = STRING_ST; act.elem[0].u.string = val.s; act.type = act_type; if (do_action(&act, msg)<0) { LOG(L_ERR,"ERROR:avpops:pushto_avp: SET_XXXX_T action" " failed\n"); goto error; } } else if (dst->opd&AVPOPS_USE_DURI) { if(set_dst_uri(msg, &val)!=0) { LOG(L_ERR,"ERROR:avpops:pushto_avp: changing dst uri " "failed\n"); goto error; } } else if (dst->opd&AVPOPS_USE_BRANCH) { if (append_branch( msg, &val, 0, 0, Q_UNSPECIFIED, 0, msg->force_send_socket)!=1 ) { LOG(L_ERR,"ERROR:avpops:pushto_avp: append_branch action" " failed\n"); goto error; } } else { LOG(L_ERR, "ERROR:avpops:pushto_avp: unknown destination\n"); goto error; } n++; if ( !(src->ops&AVPOPS_FLAG_ALL) ) break; if(avp==NULL) break; if((avp = search_first_avp( name_type, avp_name, &avp_val, avp))!=NULL) flags = avp->flags; } while (avp);/* end while */ DBG("DEBUG:avpops:pushto_avps: %d avps were processed\n",n); return 1; error: return -1; } int ops_check_avp( struct sip_msg* msg, struct fis_param* src, struct fis_param* val) { unsigned short name_type1; unsigned short name_type2; struct usr_avp *avp1; struct usr_avp *avp2; regmatch_t pmatch; int_str avp_name1; int_str avp_name2; int_str avp_val; int_str check_val; int check_flags; int n, rt; int flags; xl_value_t xvalue; char backup; /* look if the required avp(s) is/are present */ if(src->sval.type==XL_AVP) { /* search for the avp */ if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0) { LOG(L_ERR, "avpops:ops_check_avp: error getting src AVP name\n"); goto error; } avp1 = search_first_avp( name_type1, avp_name1, &avp_val, 0); if (avp1==0) { DBG("DEBUG:avpops:ops_check_avp: no src avp found\n"); goto error; } flags = avp1->flags; } else { avp1 = 0; flags = 0; if(xl_get_spec_value(msg, &(src->sval), &xvalue, 0)!=0) { LOG(L_ERR,"ERROR:avpops:ops_check_avp: cannot get src value\n"); goto error; } if(xvalue.flags&XL_TYPE_INT) { avp_val.n = xvalue.ri; } else { flags = AVP_VAL_STR; avp_val.s = xvalue.rs; } } cycle1: /* copy string since pseudo-variables uses static buffer */ if(flags&AVP_VAL_STR) { if(avp_val.s.len>=STR_BUF_SIZE) { LOG(L_ERR, "avpops:ops_check_avp: error src value too long\n"); goto error; } strncpy(str_buf, avp_val.s.s, avp_val.s.len); str_buf[avp_val.s.len] = '\0'; avp_val.s.s = str_buf; } if (val->opd&AVPOPS_VAL_PVAR) { /* the 2nd operator is variable -> get avp value */ check_flags = 0; if(val->sval.type==XL_AVP) { /* search for the avp */ if(avpops_get_aname(msg, val, &avp_name2, &name_type2)!=0) { LOG(L_ERR, "avpops:ops_check_avp: error getting dst AVP name\n"); goto error; } avp2 = search_first_avp( name_type2, avp_name2, &check_val, 0); if (avp2==0) { DBG("DEBUG:avpops:ops_check_avp: no dst avp found\n"); goto error; } check_flags = avp2->flags; } else { avp2 = 0; if(xl_get_spec_value(msg, &(val->sval), &xvalue, 0)!=0) { LOG(L_ERR,"ERROR:avpops:ops_check_avp: cannot get dst value\n"); goto error; } if(xvalue.flags&XL_TYPE_INT) { check_val.n = xvalue.ri; } else { check_flags = AVP_VAL_STR; check_val.s = xvalue.rs; } } } else { check_flags = 0; avpops_str2int_str(val->sval.p.val, check_val); if(val->sval.p.val.s) check_flags = AVP_VAL_STR; avp2 = 0; } cycle2: /* are both values of the same type? */ if ((flags&AVP_VAL_STR)^(check_flags&AVP_VAL_STR)) { LOG(L_ERR,"ERROR:avpops:check_avp: value types don't match\n"); goto next; } if (flags&AVP_VAL_STR) { /* string values to check */ DBG("DEBUG:avpops:check_avp: check <%.*s> against <%.*s> as str /%d\n", avp_val.s.len,avp_val.s.s, (val->ops&AVPOPS_OP_RE)?6:check_val.s.len, (val->ops&AVPOPS_OP_RE)?"REGEXP":check_val.s.s, val->ops); /* do check */ if (val->ops&AVPOPS_OP_EQ) { if (avp_val.s.len==check_val.s.len) { if (val->ops&AVPOPS_FLAG_CI) { if (strncasecmp(avp_val.s.s,check_val.s.s, check_val.s.len)==0) return 1; } else { if (strncmp(avp_val.s.s,check_val.s.s,check_val.s.len)==0 ) return 1; } } } else if (val->ops&AVPOPS_OP_NE) { if (avp_val.s.len!=check_val.s.len) return 1; if (val->ops&AVPOPS_FLAG_CI) { if (strncasecmp(avp_val.s.s,check_val.s.s,check_val.s.len)!=0) return 1; } else { if (strncmp(avp_val.s.s,check_val.s.s,check_val.s.len)!=0 ) return 1; } } else if (val->ops&AVPOPS_OP_LT) { n = (avp_val.s.len>=check_val.s.len)?avp_val.s.len:check_val.s.len; rt = strncasecmp(avp_val.s.s,check_val.s.s,n); if (rt<0) return 1; if(rt==0 && avp_val.s.lenops&AVPOPS_OP_LE) { n = (avp_val.s.len>=check_val.s.len)?avp_val.s.len:check_val.s.len; if (strncasecmp(avp_val.s.s,check_val.s.s,n)<=0) return 1; } else if (val->ops&AVPOPS_OP_GT) { n = (avp_val.s.len>=check_val.s.len)?avp_val.s.len:check_val.s.len; rt = strncasecmp(avp_val.s.s,check_val.s.s,n); if (rt>0) return 1; if(rt==0 && avp_val.s.len>check_val.s.len) return 1; } else if (val->ops&AVPOPS_OP_GE) { n = (avp_val.s.len>=check_val.s.len)?avp_val.s.len:check_val.s.len; if (strncasecmp(avp_val.s.s,check_val.s.s,n)>=0) return 1; } else if (val->ops&AVPOPS_OP_RE) { backup = avp_val.s.s[avp_val.s.len]; avp_val.s.s[avp_val.s.len] = '\0'; if (regexec((regex_t*)check_val.s.s, avp_val.s.s, 1, &pmatch, 0)==0) { avp_val.s.s[avp_val.s.len] = backup; return 1; } avp_val.s.s[avp_val.s.len] = backup; } else if (val->ops&AVPOPS_OP_FM){ backup = avp_val.s.s[avp_val.s.len]; avp_val.s.s[avp_val.s.len] = '\0'; if (fnmatch( check_val.s.s, avp_val.s.s, 0)==0) { avp_val.s.s[avp_val.s.len] = backup; return 1; } avp_val.s.s[avp_val.s.len] = backup; } else { LOG(L_CRIT,"BUG:avpops:check_avp: unknown operation " "(flg=%d/%d)\n",val->opd, val->ops); } } else { /* int values to check -> do check */ DBG("DEBUG:avpops:check_avp: check <%d> against <%d> as int /%d\n", avp_val.n, check_val.n, val->ops); if (val->ops&AVPOPS_OP_EQ) { if ( avp_val.n==check_val.n) return 1; } else if (val->ops&AVPOPS_OP_NE) { if ( avp_val.n!=check_val.n) return 1; } else if (val->ops&AVPOPS_OP_LT) { if ( avp_val.nops&AVPOPS_OP_LE) { if ( avp_val.n<=check_val.n) return 1; } else if (val->ops&AVPOPS_OP_GT) { if ( avp_val.n>check_val.n) return 1; } else if (val->ops&AVPOPS_OP_GE) { if ( avp_val.n>=check_val.n) return 1; } else if (val->ops&AVPOPS_OP_BAND) { if ( avp_val.n&check_val.n) return 1; } else if (val->ops&AVPOPS_OP_BOR) { if ( avp_val.n|check_val.n) return 1; } else if (val->ops&AVPOPS_OP_BXOR) { if ( avp_val.n^check_val.n) return 1; } else { LOG(L_CRIT,"BUG:avpops:check_avp: unknown operation " "(flg=%d)\n",val->ops); } } next: /* cycle for the second value (only if avp can have multiple vals) */ if ((avp2!=NULL) && (avp2=search_first_avp( name_type2, avp_name2, &check_val, avp2))!=NULL) { check_flags = avp2->flags; goto cycle2; /* cycle for the first value -> next avp */ } else { if(avp1 && val->ops&AVPOPS_FLAG_ALL) { avp1=search_first_avp(name_type1, avp_name1, &avp_val, avp1); if (avp1) goto cycle1; } } DBG("DEBUG:avpops:check_avp: no match\n"); return -1; /* check failed */ error: return -1; } int ops_print_avp() { struct usr_avp **avp_list; struct usr_avp *avp; int_str val; str *name; /* go through all list */ avp_list = get_avp_list(); avp = *avp_list; for ( ; avp ; avp=avp->next) { LOG(L_INFO,"INFO:avpops:print_avp: p=%p, flags=0x%04X\n",avp, avp->flags); if (avp->flags&AVP_NAME_STR) { name = get_avp_name(avp); LOG(L_INFO,"INFO:\t\t\tname=<%.*s>\n",name->len,name->s); } else { LOG(L_INFO,"INFO:\t\t\tid=<%d>\n",avp->id); } get_avp_val( avp, &val); if (avp->flags&AVP_VAL_STR) { LOG(L_INFO,"INFO:\t\t\tval_str=<%.*s / %d>\n",val.s.len,val.s.s, val.s.len); } else { LOG(L_INFO,"INFO:\t\t\tval_int=<%d>\n",val.n); } } return 1; } int ops_printf(struct sip_msg* msg, struct fis_param* dest, xl_elem_t *format) { int printbuf_len; int_str avp_val; int_str avp_name; unsigned short flags; unsigned short name_type; if(msg==NULL || dest==NULL || format==NULL) { LOG(L_ERR, "avpops:ops_printf: error - bad parameters\n"); return -1; } printbuf_len = AVP_PRINTBUF_SIZE-1; if(xl_printf(msg, format, printbuf, &printbuf_len)<0) { LOG(L_ERR, "avpops:ops_printf: error - cannot print the format\n"); return -1; } avp_val.s.s = printbuf; avp_val.s.len = printbuf_len; /* set the proper flag */ flags = AVP_VAL_STR; /* is dynamic avp name ? */ if(avpops_get_aname(msg, dest, &avp_name, &name_type)!=0) { LOG(L_ERR, "BUG:avpops:ops_printf: error getting dst AVP name\n"); return -1; } if(name_type == AVP_NAME_STR) flags |= AVP_NAME_STR; if (add_avp(flags, avp_name, avp_val)<0) { LOG(L_ERR, "avpops:ops_printf: error - cannot add AVP\n"); return -1; } return 1; } int ops_subst(struct sip_msg* msg, struct fis_param** src, struct subst_expr* se) { struct usr_avp *avp; struct usr_avp *prev_avp; int_str avp_val; unsigned short name_type1; unsigned short name_type2; int_str avp_name1; int_str avp_name2; int n; int nmatches; str* result; n = 0; prev_avp = 0; /* avp name is known ->search by name */ /* get src avp name */ if(avpops_get_aname(msg, src[0], &avp_name1, &name_type1)!=0) { LOG(L_ERR, "BUG:avpops:ops_subst: error getting src AVP name\n"); return -1; } avp = search_first_avp(name_type1, avp_name1, &avp_val, 0); if(avp==NULL) return -1; if(src[1]!=0) { /* get dst avp name */ if(avpops_get_aname(msg, src[1], &avp_name2, &name_type2)!=0) { LOG(L_ERR, "BUG:avpops:ops_subst: error getting dst AVP name\n"); return -1; } } else { name_type2 = name_type1; avp_name2 = avp_name1; } if(name_type2&AVP_NAME_STR) { if(avp_name2.s.len>=STR_BUF_SIZE) { LOG(L_ERR, "avpops:ops_subst: error dst name too long\n"); goto error; } strncpy(str_buf, avp_name2.s.s, avp_name2.s.len); str_buf[avp_name2.s.len] = '\0'; avp_name2.s.s = str_buf; } while(avp) { if(!is_avp_str_val(avp)) { prev_avp = avp; avp = search_first_avp(name_type1, avp_name1, &avp_val, prev_avp); continue; } result=subst_str(avp_val.s.s, msg, se, &nmatches); if(result!=NULL) { /* build a new avp with new name */ avp_val.s = *result; if(add_avp(name_type2|AVP_VAL_STR, avp_name2, avp_val)==-1 ) { LOG(L_ERR,"ERROR:avpops:ops_subst: failed to create new avp\n"); if(result->s!=0) pkg_free(result->s); pkg_free(result); goto error; } if(result->s!=0) pkg_free(result->s); pkg_free(result); n++; /* copy all avps? */ if (!(src[0]->ops&AVPOPS_FLAG_ALL) ) { /* delete the old one? */ if (src[0]->ops&AVPOPS_FLAG_DELETE || src[1]==0) destroy_avp(avp); break; } else { prev_avp = avp; avp = search_first_avp(name_type1,avp_name1,&avp_val,prev_avp); /* delete the old one? */ if (src[0]->ops&AVPOPS_FLAG_DELETE || src[1]==0) destroy_avp( prev_avp ); } } else { prev_avp = avp; avp = search_first_avp(name_type1, avp_name1, &avp_val, prev_avp); } } DBG("avpops:ops_subst: subst to %d avps\n", n); return n?1:-1; error: return -1; } int ops_op_avp( struct sip_msg* msg, struct fis_param** av, struct fis_param* val) { unsigned short name_type1; unsigned short name_type2; unsigned short name_type3; struct fis_param* src; struct usr_avp *avp1; struct usr_avp *avp2; struct usr_avp *prev_avp; int_str avp_name1; int_str avp_name2; int_str avp_name3; int_str avp_val; int_str op_val; int op_flags; int result; xl_value_t xvalue; src = av[0]; /* look if the required avp(s) is/are present */ /* search for the avp */ if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0) { LOG(L_ERR, "avpops:ops_op_avp: error getting src AVP name\n"); goto error; } avp1 = search_first_avp(name_type1, avp_name1, &avp_val, 0); if (avp1==0) { DBG("DEBUG:avpops:ops_op_avp: no src avp found\n"); goto error; } while(avp1!=0) { if(!(avp1->flags&AVP_VAL_STR)) break; avp1 = search_first_avp(name_type1, avp_name1, &avp_val, avp1); } if (avp1==0 && !(val->ops&AVPOPS_OP_BNOT)) { DBG("DEBUG:avpops:op_avp: no proper avp found\n"); goto error; } name_type3 = name_type1; avp_name3 = avp_name1; if(av[1]!=0) { if(avpops_get_aname(msg, av[1], &avp_name3, &name_type3)!=0) { LOG(L_ERR, "avpops:ops_op_avp: error getting dst AVP name\n"); goto error; } } if(name_type3&AVP_NAME_STR) { if(avp_name3.s.len>=STR_BUF_SIZE) { LOG(L_ERR, "avpops:ops_op_avp: error dst name too long\n"); goto error; } strncpy(str_buf, avp_name3.s.s, avp_name3.s.len); str_buf[avp_name3.s.len] = '\0'; avp_name3.s.s = str_buf; } prev_avp = 0; result = 0; cycle1: if (val->opd&AVPOPS_VAL_PVAR) { /* the 2nd operator is variable -> get value */ op_flags = 0; if(val->sval.type==XL_AVP) { /* search for the avp */ if(avpops_get_aname(msg, val, &avp_name2, &name_type2)!=0) { LOG(L_ERR, "avpops:ops_op_avp: error getting dst AVP name\n"); goto error; } avp2 = search_first_avp( name_type2, avp_name2, &op_val, 0); while(avp2!=0) { if(!(avp2->flags&AVP_VAL_STR)) break; avp2 = search_first_avp( name_type2, avp_name2, &op_val, avp2); } if (avp2==0) { DBG("DEBUG:avpops:op_avp: no dst avp found\n"); goto error; } } else { avp2 = 0; if(xl_get_spec_value(msg, &(val->sval), &xvalue, 0)!=0) { LOG(L_ERR,"ERROR:avpops:ops_op_avp: cannot get dst value\n"); goto error; } if(xvalue.flags&XL_TYPE_INT) { op_val.n = xvalue.ri; } else { LOG(L_ERR, "ERROR:avpops:ops_op_avp: error - dst value is str\n"); goto error; } } } else { avpops_str2int_str(val->sval.p.val, op_val); avp2 = 0; } cycle2: /* do operation */ DBG("DEBUG:avpops:op_avp: use <%d> and <%d>\n", avp_val.n, op_val.n); if (val->ops&AVPOPS_OP_ADD) { result = avp_val.n+op_val.n; } else if (val->ops&AVPOPS_OP_SUB) { result = avp_val.n-op_val.n; } else if (val->ops&AVPOPS_OP_MUL) { result = avp_val.n*op_val.n; } else if (val->ops&AVPOPS_OP_DIV) { if(op_val.n!=0) result = (int)(avp_val.n/op_val.n); else { LOG(L_ERR, "avpops:op_avp: error - division by 0\n"); result = 0; } } else if (val->ops&AVPOPS_OP_MOD) { if(op_val.n!=0) result = avp_val.n%op_val.n; else { LOG(L_ERR, "avpops:op_avp: error - modulo by 0\n"); result = 0; } } else if (val->ops&AVPOPS_OP_BAND) { result = avp_val.n&op_val.n; } else if (val->ops&AVPOPS_OP_BOR) { result = avp_val.n|op_val.n; } else if (val->ops&AVPOPS_OP_BXOR) { result = avp_val.n^op_val.n; } else if (val->ops&AVPOPS_OP_BNOT) { result = ~op_val.n; } else { LOG(L_CRIT,"BUG:avpops:op_avp: unknown operation " "(flg=%d)\n",val->ops); goto error; } /* add the new avp */ avp_val.n = result; if(add_avp(name_type3, avp_name3, avp_val)==-1 ) { LOG(L_ERR,"ERROR:avpops:op_avp: failed to create new avp\n"); goto error; } /* cycle for the second value (only if avp can have multiple vals) */ while((avp2!=NULL) &&(avp2=search_first_avp( name_type2, avp_name2, &op_val, avp2))!=0) { if(!(avp2->flags&AVP_VAL_STR)) goto cycle2; } prev_avp = avp1; /* cycle for the first value -> next avp */ while((avp1!=NULL) &&(avp1=search_first_avp(name_type1, avp_name1, &avp_val, avp1))!=0) { if (!(avp1->flags&AVP_VAL_STR)) { if(val->ops&AVPOPS_FLAG_DELETE && prev_avp!=0) { destroy_avp(prev_avp); prev_avp = 0; } goto cycle1; } } DBG("DEBUG:avpops:op_avp: done\n"); if(val->ops&AVPOPS_FLAG_DELETE && prev_avp!=0) { destroy_avp(prev_avp); prev_avp = 0; } return 1; error: return -1; } int ops_is_avp_set(struct sip_msg* msg, struct fis_param *ap) { struct usr_avp *avp; unsigned short name_type; int_str avp_name; int_str avp_value; int index; /* get avp name */ if(avpops_get_aname(msg, ap, &avp_name, &name_type)!=0) { LOG(L_ERR, "avpops:is_avp_set: error getting AVP name\n"); return -1; } /* get avp index */ if(xl_get_spec_index(&ap->sval, &index)!=0) { LOG(L_ERR, "avpops:is_avp_set: error getting AVP index\n"); return -1; } avp=search_first_avp(name_type, avp_name, &avp_value, 0); if(avp==0) return -1; do { /* last index [-1] or all [*] go here as well */ if(index<=0) { if(ap->ops&AVPOPS_FLAG_ALL) return 1; if((ap->ops&AVPOPS_FLAG_CASTS && !(avp->flags&AVP_VAL_STR)) ||(ap->ops&AVPOPS_FLAG_CASTN && avp->flags&AVP_VAL_STR)) return -1; if(ap->ops&AVPOPS_FLAG_EMPTY) { if(avp->flags&AVP_VAL_STR) { if(avp_value.s.s==0 || avp_value.s.len==0) return 1; else return -1; } else { if(avp_value.n==0) return 1; else return -1; } } return 1; } index--; } while ((avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0); return -1; }