2 * Copyright (C) 2001-2003 FhG Fokus
4 * This file is part of Kamailio, a free SIP server.
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * \brief Kamailio core :: Attribute value pair handling (AVP)
37 #include "sr_module.h"
41 #include "mem/shm_mem.h"
59 struct avp_galias *next;
62 static struct avp_galias *galiases = 0;
64 static avp_list_t def_list[IDX_MAX]; /* Default AVP lists */
65 static avp_list_t* crt_list[IDX_MAX]; /* Pointer to current AVP lists */
67 /* Global AVP related variables go to shm mem */
68 static avp_list_t* def_glist;
69 static avp_list_t** crt_glist;
72 int registered_avpflags_no = 0;
73 static char *registered_avpflags[MAX_AVPFLAG];
75 /* Initialize AVP lists in private memory and allocate memory
81 /* Empty default lists */
82 memset(def_list, 0, sizeof(avp_list_t) * IDX_MAX);
84 /* Point current pointers to default lists */
85 for(i = 0; i < IDX_MAX; i++) {
86 crt_list[i] = &def_list[i];
89 def_glist = (avp_list_t*)shm_malloc(sizeof(avp_list_t));
90 crt_glist = (avp_list_t**)shm_malloc(sizeof(avp_list_t*));
91 if (!def_glist || !crt_glist) {
96 *crt_glist = def_glist;
102 * Select active AVP list based on the value of flags
104 static avp_list_t* select_list(avp_flags_t flags)
106 if (flags & AVP_CLASS_URI) {
107 if (flags & AVP_TRACK_TO) {
108 return crt_list[IDX_TO_URI];
110 return crt_list[IDX_FROM_URI];
112 } else if (flags & AVP_CLASS_USER) {
113 if (flags & AVP_TRACK_TO) {
114 return crt_list[IDX_TO_USER];
116 return crt_list[IDX_FROM_USER];
118 } else if (flags & AVP_CLASS_DOMAIN) {
119 if (flags & AVP_TRACK_TO) {
120 return crt_list[IDX_TO_DOMAIN];
122 return crt_list[IDX_FROM_DOMAIN];
124 } else if (flags & AVP_CLASS_GLOBAL) {
131 inline static avp_id_t compute_ID( str *name )
137 for( p=name->s+name->len-1 ; p>=name->s ; p-- )
143 avp_t *create_avp (avp_flags_t flags, avp_name_t name, avp_value_t val)
147 struct str_int_data *sid;
148 struct str_str_data *ssd;
151 if (name.s.s == NULL || name.s.len == 0) {
152 LM_ERR("0 ID or NULL NAME AVP!");
156 /* compute the required mem size */
157 len = sizeof(struct usr_avp);
158 if (flags&AVP_NAME_STR) {
159 if ( name.s.s==0 || name.s.len==0) {
160 LM_ERR("EMPTY NAME AVP!");
163 if (flags&AVP_VAL_STR) {
164 len += sizeof(struct str_str_data)-sizeof(union usr_avp_data)
165 + name.s.len + 1 /* Terminating zero for regex search */
166 + val.s.len + 1; /* Value is zero terminated */
168 len += sizeof(struct str_int_data)-sizeof(union usr_avp_data)
169 + name.s.len + 1; /* Terminating zero for regex search */
171 } else if (flags&AVP_VAL_STR) {
172 len += sizeof(str)-sizeof(union usr_avp_data) + val.s.len + 1;
175 avp = (struct usr_avp*)shm_malloc( len );
182 avp->id = (flags&AVP_NAME_STR)? compute_ID(&name.s) : name.n ;
185 switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) )
188 /* avp type ID, int value */
192 /* avp type str, int value */
193 sid = (struct str_int_data*)&avp->d.data[0];
195 sid->name.len =name.s.len;
196 sid->name.s = (char*)sid + sizeof(struct str_int_data);
197 memcpy( sid->name.s , name.s.s, name.s.len);
198 sid->name.s[name.s.len] = '\0'; /* Zero terminator */
201 /* avp type ID, str value */
202 s = (str*)&avp->d.data[0];
204 s->s = (char*)s + sizeof(str);
205 memcpy( s->s, val.s.s , s->len);
208 case AVP_NAME_STR|AVP_VAL_STR:
209 /* avp type str, str value */
210 ssd = (struct str_str_data*)&avp->d.data[0];
211 ssd->name.len = name.s.len;
212 ssd->name.s = (char*)ssd + sizeof(struct str_str_data);
213 memcpy( ssd->name.s , name.s.s, name.s.len);
214 ssd->name.s[name.s.len]='\0'; /* Zero terminator */
215 ssd->val.len = val.s.len;
216 ssd->val.s = ssd->name.s + ssd->name.len + 1;
217 memcpy( ssd->val.s , val.s.s, val.s.len);
218 ssd->val.s[ssd->val.len] = 0;
226 int add_avp_list(avp_list_t* list, avp_flags_t flags, avp_name_t name, avp_value_t val)
232 if ((avp = create_avp(flags, name, val))) {
242 int add_avp(avp_flags_t flags, avp_name_t name, avp_value_t val)
244 avp_flags_t avp_class;
247 /* Add avp to uri class if no class has been
248 * specified by the caller
250 if ((flags & AVP_CLASS_ALL) == 0) flags |= AVP_CLASS_URI;
251 if ((flags & AVP_TRACK_ALL) == 0) flags |= AVP_TRACK_FROM;
252 if (!(list = select_list(flags)))
255 if (flags & AVP_CLASS_URI) avp_class = AVP_CLASS_URI;
256 else if (flags & AVP_CLASS_USER) avp_class = AVP_CLASS_USER;
257 else if (flags & AVP_CLASS_DOMAIN) avp_class = AVP_CLASS_DOMAIN;
258 else avp_class = AVP_CLASS_GLOBAL;
260 /* Make that only the selected class is set
261 * if the caller set more classes in flags
263 return add_avp_list(list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val);
266 int add_avp_before(avp_t *avp, avp_flags_t flags, avp_name_t name, avp_value_t val)
271 return add_avp(flags, name, val);
274 if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
275 if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
277 if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
278 LM_ERR("Source and target AVPs have different CLASS/TRACK\n");
281 if ((new_avp=create_avp(flags, name, val))) {
282 new_avp->next=avp->next;
289 /* get value functions */
290 inline str* get_avp_name(avp_t *avp)
292 struct str_int_data *sid;
293 struct str_str_data *ssd;
295 switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) )
298 /* avp type ID, int value */
300 /* avp type ID, str value */
303 /* avp type str, int value */
304 sid = (struct str_int_data*)&avp->d.data[0];
306 case AVP_NAME_STR|AVP_VAL_STR:
307 /* avp type str, str value */
308 ssd = (struct str_str_data*)&avp->d.data[0];
312 LM_ERR("unknown avp type (name&val) %d\n", avp->flags&(AVP_NAME_STR|AVP_VAL_STR));
317 inline void get_avp_val(avp_t *avp, avp_value_t *val)
320 struct str_int_data *sid;
321 struct str_str_data *ssd;
323 if (avp==0 || val==0)
326 switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) ) {
328 /* avp type ID, int value */
332 /* avp type str, int value */
333 sid = (struct str_int_data*)&avp->d.data[0];
337 /* avp type ID, str value */
338 s = (str*)&avp->d.data[0];
341 case AVP_NAME_STR|AVP_VAL_STR:
342 /* avp type str, str value */
343 ssd = (struct str_str_data*)&avp->d.data[0];
350 /* Return the current list of user attributes */
351 avp_list_t get_avp_list(avp_flags_t flags)
355 list = select_list(flags);
356 return (list ? *list : NULL);
361 * Compare given id with id in avp, return true if they match
363 static inline int match_by_id(avp_t* avp, avp_id_t id)
365 if (avp->id == id && (avp->flags&AVP_NAME_STR)==0) {
373 * Compare given name with name in avp, return true if they are same
375 static inline int match_by_name(avp_t* avp, avp_id_t id, str* name)
378 if (id==avp->id && avp->flags&AVP_NAME_STR &&
379 (avp_name=get_avp_name(avp))!=0 && avp_name->len==name->len
380 && !strncasecmp( avp_name->s, name->s, name->len) ) {
388 * Compare name with name in AVP using regular expressions, return
391 static inline int match_by_re(avp_t* avp, regex_t* re)
395 /* AVP identifiable by name ? */
396 if (!(avp->flags&AVP_NAME_STR)) return 0;
397 if ((avp_name=get_avp_name(avp))==0) /* valid AVP name ? */
399 if (!avp_name->s) /* AVP name validation */
401 if (regexec(re, avp_name->s, 1, &pmatch,0)==0) { /* re match ? */
408 avp_t *search_first_avp(avp_flags_t flags, avp_name_t name, avp_value_t *val, struct search_state* s)
414 return search_avp (id, val, s);
417 avp_t *search_avp (avp_ident_t ident, avp_value_t* val, struct search_state* state)
420 static struct search_state st;
423 if (ident.name.s.s==0 && ident.name.s.len == 0) {
424 LM_ERR("0 ID or NULL NAME AVP!");
428 switch (ident.flags & AVP_INDEX_ALL) {
429 case AVP_INDEX_BACKWARD:
430 case AVP_INDEX_FORWARD:
431 WARN("AVP specified with index, but not used for search\n");
436 memset(&st, 0, sizeof(struct search_state));
440 if ((ident.flags & AVP_CLASS_ALL) == 0) {
441 /* The caller did not specify any class to search in, so enable
442 * all of them by default
444 ident.flags |= AVP_CLASS_ALL;
446 if ((ident.flags & AVP_TRACK_ALL) == 0) {
447 /* The caller did not specify even the track to search in, so search
450 ident.flags |= AVP_TRACK_FROM;
454 if (!(list = select_list(ident.flags)))
457 state->flags = ident.flags;
459 state->name = ident.name;
461 if(ident.flags & AVP_NAME_STR) {
462 state->id = compute_ID(&ident.name.s);
465 ret = search_next_avp(state, val);
467 /* Make sure that search next avp stays in the same class as the first
471 (ident.flags & ~AVP_CLASS_ALL) | (ret->flags & AVP_CLASS_ALL);
476 avp_t *search_next_avp(struct search_state* s, avp_value_t *val )
483 LM_ERR("Invalid parameter value\n");
487 switch (s->flags & AVP_INDEX_ALL) {
488 case AVP_INDEX_BACKWARD:
489 case AVP_INDEX_FORWARD:
490 WARN("AVP specified with index, but not used for search\n");
495 for( ; s->avp; s->avp = s->avp->next) {
496 if (s->flags & AVP_NAME_RE) {
497 matched = match_by_re(s->avp, s->name.re);
498 } else if (s->flags & AVP_NAME_STR) {
499 matched = match_by_name(s->avp, s->id, &s->name.s);
501 matched = match_by_id(s->avp, s->name.n);
505 s->avp = s->avp->next;
506 if (val) get_avp_val(avp, val);
511 if (s->flags & AVP_CLASS_URI) {
512 s->flags &= ~AVP_CLASS_URI;
513 list = select_list(s->flags);
514 } else if (s->flags & AVP_CLASS_USER) {
515 s->flags &= ~AVP_CLASS_USER;
516 list = select_list(s->flags);
517 } else if (s->flags & AVP_CLASS_DOMAIN) {
518 s->flags &= ~AVP_CLASS_DOMAIN;
519 list = select_list(s->flags);
521 s->flags &= ~AVP_CLASS_GLOBAL;
531 int search_reverse( avp_t *cur, struct search_state* st,
532 avp_index_t index, avp_list_t *ret)
538 lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1;
544 avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
545 avp_value_t *val, avp_index_t index)
548 struct search_state st;
550 if (flags & AVP_NAME_RE) {
551 BUG("search_by_index not supported for AVP_NAME_RE\n");
554 switch (flags & AVP_INDEX_ALL) {
556 ret = search_first_avp(flags, name, val, &st);
557 if (!ret || search_next_avp(&st, NULL))
562 BUG("search_by_index not supported for anonymous index []\n");
564 case AVP_INDEX_FORWARD:
566 cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st);
567 search_reverse(cur, &st, index, &ret);
569 get_avp_val(ret, val);
571 case AVP_INDEX_BACKWARD:
572 ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st);
573 for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
581 /********* free functions ********/
583 void destroy_avp(avp_t *avp_del)
586 avp_t *avp, *avp_prev;
588 for (i = 0; i < IDX_MAX; i++) {
589 for( avp_prev=0,avp=*crt_list[i] ; avp ;
590 avp_prev=avp,avp=avp->next ) {
593 avp_prev->next=avp->next;
595 *crt_list[i] = avp->next;
603 for( avp_prev=0,avp=**crt_glist ; avp ;
604 avp_prev=avp,avp=avp->next ) {
607 avp_prev->next=avp->next;
609 **crt_glist = avp->next;
618 void destroy_avp_list_unsafe(avp_list_t* list)
626 shm_free_unsafe( foo );
632 inline void destroy_avp_list(avp_list_t* list)
636 LM_DBG("destroying list %p\n", *list);
646 int reset_avp_list(int flags)
649 if (flags & AVP_CLASS_URI) {
650 if (flags & AVP_TRACK_FROM) i = IDX_FROM_URI;
652 } else if (flags & AVP_CLASS_USER) {
653 if (flags & AVP_TRACK_FROM) i = IDX_FROM_USER;
654 else i = IDX_TO_USER;
655 } else if (flags & AVP_CLASS_DOMAIN) {
656 if (flags & AVP_TRACK_FROM) i = IDX_FROM_DOMAIN;
657 else i = IDX_TO_DOMAIN;
660 crt_list[i] = &def_list[i];
661 destroy_avp_list(crt_list[i]);
665 void reset_avps(void)
668 for(i = 0; i < IDX_MAX; i++) {
669 crt_list[i] = &def_list[i];
670 destroy_avp_list(crt_list[i]);
675 avp_list_t* set_avp_list( avp_flags_t flags, avp_list_t* list )
679 if (flags & AVP_CLASS_URI) {
680 if (flags & AVP_TRACK_FROM) {
681 prev = crt_list[IDX_FROM_URI];
682 crt_list[IDX_FROM_URI] = list;
684 prev = crt_list[IDX_TO_URI];
685 crt_list[IDX_TO_URI] = list;
687 } else if (flags & AVP_CLASS_USER) {
688 if (flags & AVP_TRACK_FROM) {
689 prev = crt_list[IDX_FROM_USER];
690 crt_list[IDX_FROM_USER] = list;
692 prev = crt_list[IDX_TO_USER];
693 crt_list[IDX_TO_USER] = list;
695 } else if (flags & AVP_CLASS_DOMAIN) {
696 if (flags & AVP_TRACK_FROM) {
697 prev = crt_list[IDX_FROM_DOMAIN];
698 crt_list[IDX_FROM_DOMAIN] = list;
700 prev = crt_list[IDX_TO_DOMAIN];
701 crt_list[IDX_TO_DOMAIN] = list;
712 /********* global aliases functions ********/
714 static inline int check_avp_galias(str *alias, int type, int_str avp_name)
716 struct avp_galias *ga;
718 type &= AVP_NAME_STR;
720 for( ga=galiases ; ga ; ga=ga->next ) {
721 /* check for duplicated alias names */
722 if ( alias->len==ga->alias.len &&
723 (strncasecmp( alias->s, ga->alias.s, alias->len)==0) )
725 /*check for duplicated avp names */
726 if (type==ga->avp.type) {
727 if (type&AVP_NAME_STR){
728 if (avp_name.s.len==ga->avp.name.s.len &&
729 (strncasecmp(avp_name.s.s, ga->avp.name.s.s,
730 avp_name.s.len)==0) )
733 if (avp_name.n==ga->avp.name.n)
742 int add_avp_galias(str *alias, int type, int_str avp_name)
744 struct avp_galias *ga;
746 if ((type&AVP_NAME_STR && (!avp_name.s.s ||
747 !avp_name.s.len)) ||!alias || !alias->s ||
749 LM_ERR("null params received\n");
753 if (check_avp_galias(alias,type,avp_name)!=0) {
754 LM_ERR("duplicate alias/avp entry\n");
758 ga = (struct avp_galias*)pkg_malloc( sizeof(struct avp_galias) );
764 ga->alias.s = (char*)pkg_malloc( alias->len+1 );
765 if (ga->alias.s==0) {
769 memcpy( ga->alias.s, alias->s, alias->len);
770 ga->alias.len = alias->len;
772 ga->avp.type = type&AVP_NAME_STR;
774 if (type&AVP_NAME_STR) {
775 ga->avp.name.s.s = (char*)pkg_malloc( avp_name.s.len+1 );
776 if (ga->avp.name.s.s==0) {
780 ga->avp.name.s.len = avp_name.s.len;
781 memcpy( ga->avp.name.s.s, avp_name.s.s, avp_name.s.len);
782 ga->avp.name.s.s[avp_name.s.len] = 0;
783 LM_DBG("registering <%s> for avp name <%s>\n",
784 ga->alias.s, ga->avp.name.s.s);
786 ga->avp.name.n = avp_name.n;
787 LM_DBG("registering <%s> for avp id <%d>\n",
788 ga->alias.s, ga->avp.name.n);
796 pkg_free(ga->alias.s);
804 int lookup_avp_galias(str *alias, int *type, int_str *avp_name)
806 struct avp_galias *ga;
808 for( ga=galiases ; ga ; ga=ga->next )
809 if (alias->len==ga->alias.len &&
810 (strncasecmp( alias->s, ga->alias.s, alias->len)==0) ) {
811 *type = ga->avp.type;
812 *avp_name = ga->avp.name;
820 /* parsing functions */
821 #define ERR_IF_CONTAINS(name,chr) \
822 if (memchr(name->s,chr,name->len)) { \
823 LM_ERR("Unexpected control character '%c' in AVP name\n", chr); \
827 int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
832 ret=parse_avp_ident(name, &attr);
834 if (type) *type = attr.flags;
835 if (avp_name) *avp_name = attr.name;
836 if (index) *index = attr.index;
842 /** parse an avp indentifier.
844 * Parses the following avp indentifier forms:
845 * - "i:<number>" - old form, deprecated (e.g. i:42)
846 * - "s:<string>" - old form, deprecated (e.g. s:foo)
847 * - "<track>.<name>" (e.g.: f.bar)
848 * - "<track>.<name>[<index>]" (e.g.: f.bar[1])
849 * - "<track><class>.<name>" (e.g: tu.bar)
850 * - "<track><class>.<name>[<index>]" (e.g: fd.bar[2])
851 * - "<string>" (e.g.: foo)
853 * \<string\> = ascii string
854 * \<id\> = ascii string w/o '[', ']', '.' and '/'
855 * \<name\> = \<id\> | '/' regex '/'
856 * (Note: regex use is deprecated)
857 * \<track\> = 'f' | 't'
859 * \<class\> = 'r' | 'u' | 'd' | 'g'
860 * (uri, user, domain or global)
861 * \<index\> = \<number\> | '-' \<number\> | ''
862 * (the avp index, if missing it means AVP_INDEX_ALL, but
863 * it's use is deprecated)
865 * "fr.bar[1]" - from track, uri class, avp "bar", the value 1.
866 * "tu./^foo/" - to track, user class, all avps for which the name
867 * starts with foo (note RE in avp names are deprecated).
868 * "t.did" - to track, "did" avp
870 * @param name - avp identifier
871 * @param *attr - the result will be stored here
872 * @return 0 on success, -1 on error
874 int parse_avp_ident( str *name, avp_ident_t* attr)
881 if (name==0 || name->s==0 || name->len==0) {
882 LM_ERR("NULL name or name->s or name->len\n");
887 LM_DBG("Parsing '%.*s'\n", name->len, name->s);
888 if (name->len>=2 && name->s[1]==':') { /* old fashion i: or s: */
889 /* WARN("i: and s: avp name syntax is deprecated!\n"); */
897 attr->flags = AVP_NAME_STR;
898 attr->name.s = *name;
902 if (str2int( name, &id)!=0) {
903 LM_ERR("invalid ID <%.*s> - not a number\n",
907 attr->name.n = (int)id;
910 LM_ERR("unsupported type [%c]\n", c);
913 } else if ((p=memchr(name->s, '.', name->len))) {
918 } else if (p-name->s==2) {
919 id=name->s[0]<<8 | name->s[1];
923 LM_ERR("AVP unknown class prefix '%.*s'\n", name->len, name->s);
927 LM_ERR("AVP name not specified after the prefix separator\n");
932 attr->flags = AVP_TRACK_FROM;
935 attr->flags = AVP_TRACK_TO;
937 case 0x6672: /* 'fr' */
938 attr->flags = AVP_TRACK_FROM | AVP_CLASS_URI;
940 case 0x7472: /* 'tr' */
941 attr->flags = AVP_TRACK_TO | AVP_CLASS_URI;
943 case 0x6675: /* 'fu' */
944 attr->flags = AVP_TRACK_FROM | AVP_CLASS_USER;
946 case 0x7475: /* 'tu' */
947 attr->flags = AVP_TRACK_TO | AVP_CLASS_USER;
949 case 0x6664: /* 'fd' */
950 attr->flags = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
952 case 0x7464: /* 'td' */
953 attr->flags = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
956 attr->flags = AVP_TRACK_ALL | AVP_CLASS_GLOBAL;
960 LM_ERR("AVP unknown class prefix '%c'\n", id);
962 LM_ERR("AVP unknown class prefix '%c%c'\n", id>>8,id);
965 if (name->s[name->len-1]==']') {
966 p=memchr(name->s, '[', name->len);
968 LM_ERR("missing '[' for AVP index\n");
972 s.len=name->len-(p-name->s)-2; /* [ and ] */
974 attr->flags |= AVP_INDEX_ALL;
977 attr->flags |= AVP_INDEX_BACKWARD;
980 attr->flags |= AVP_INDEX_FORWARD;
982 if ((str2int(&s, &id) != 0)||(id==0)) {
983 LM_ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
990 ERR_IF_CONTAINS(name,'.');
991 ERR_IF_CONTAINS(name,'[');
992 ERR_IF_CONTAINS(name,']');
993 if ((name->len > 2) && (name->s[0]=='/') && (name->s[name->len-1]=='/')) {
994 attr->name.re=pkg_malloc(sizeof(regex_t));
995 if (!attr->name.re) {
999 name->s[name->len-1]=0;
1000 if (regcomp(attr->name.re, name->s+1, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
1001 pkg_free(attr->name.re);
1003 name->s[name->len-1] = '/';
1006 name->s[name->len-1] = '/';
1007 attr->flags |= AVP_NAME_RE;
1009 ERR_IF_CONTAINS(name,'/');
1010 attr->flags |= AVP_NAME_STR;
1011 attr->name.s = *name;
1014 /*default is string name*/
1015 attr->flags = AVP_NAME_STR;
1016 attr->name.s = *name;
1024 void free_avp_ident(avp_ident_t* attr)
1026 if (attr->flags & AVP_NAME_RE) {
1027 if (! attr->name.re) {
1028 BUG("attr ident @%p has the regexp flag set, but no regexp.\n",
1034 regfree(attr->name.re);
1035 pkg_free(attr->name.re);
1040 int km_parse_avp_spec( str *name, int *type, int_str *avp_name)
1045 if (name==0 || name->s==0 || name->len==0)
1048 p = (char*)memchr((void*)name->s, ':', name->len);
1050 /* might be kamailio avp alias or ser avp name style */
1051 if(lookup_avp_galias( name, type, avp_name)==0)
1052 return 0; /* found */
1054 return parse_avp_name( name, type, avp_name, &index);
1058 int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index)
1062 if (name==0 || name->s==0 || name->len==0)
1065 if (name->s[0]==GALIAS_CHAR_MARKER) {
1066 /* it's an avp alias */
1068 LM_ERR("empty alias\n");
1071 alias.s = name->s+1;
1072 alias.len = name->len-1;
1073 return lookup_avp_galias( &alias, type, avp_name);
1075 return parse_avp_name( name, type, avp_name, index);
1079 void free_avp_name(avp_flags_t *type, int_str *avp_name)
1081 if ((*type & AVP_NAME_RE) && (avp_name->re)){
1082 regfree(avp_name->re);
1083 pkg_free(avp_name->re);
1088 int add_avp_galias_str(char *alias_definition)
1097 s = alias_definition;
1098 while(*s && isspace((int)*s))
1102 /* parse alias name */
1104 while(*s && *s!=';' && !isspace((int)*s) && *s!='=')
1106 if (alias.s==s || *s==0 || *s==';')
1108 alias.len = s-alias.s;
1109 while(*s && isspace((int)*s))
1115 while(*s && isspace((int)*s))
1119 while(*s && *s!=';' && !isspace((int)*s))
1123 name.len = s-name.s;
1124 while(*s && isspace((int)*s))
1127 if (*s!=0 && *s!=';')
1130 for( s++ ; *s && isspace((int)*s) ; s++ );
1135 if (parse_avp_name( &name, &type, &avp_name, &index)!=0) {
1136 LM_ERR("<%.*s> not a valid AVP name\n", name.len, name.s);
1140 if (add_avp_galias( &alias, type, avp_name)!=0) {
1141 LM_ERR("add global alias failed\n");
1148 LM_ERR("parse error in <%s> around pos %ld\n",
1149 alias_definition, (long)(s-alias_definition));
1155 int destroy_avps(avp_flags_t flags, avp_name_t name, int all)
1157 struct search_state st;
1162 avp = search_first_avp(flags, name, 0, &st);
1167 avp = search_next_avp(&st, 0);
1173 void delete_avp(avp_flags_t flags, avp_name_t name)
1175 struct search_state st;
1178 avp = search_first_avp(flags, name, 0, &st);
1181 avp = search_next_avp(&st, 0);
1185 /* AVP flags functions */
1187 /* name2id conversion is intended to use during fixup (cfg parsing and modinit) only therefore no hash is used */
1188 avp_flags_t register_avpflag(char* name) {
1190 ret = get_avpflag_no(name);
1192 if (registered_avpflags_no >= MAX_AVPFLAG) {
1193 LM_ERR("cannot register new avp flag ('%s'), max.number of flags (%d) reached\n",
1197 ret = 1<<(AVP_CUSTOM_FLAGS+registered_avpflags_no);
1198 registered_avpflags[registered_avpflags_no++] = name;
1203 avp_flags_t get_avpflag_no(char* name) {
1205 for (i=0; i<registered_avpflags_no; i++) {
1206 if (strcasecmp(name, registered_avpflags[i])==0)
1207 return 1<<(AVP_CUSTOM_FLAGS+i);