flags.c
3881f12c
 /*
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
6a0f4382
  * This file is part of Kamailio, a free SIP server.
7dd0b342
  *
6a0f4382
  * Kamailio is free software; you can redistribute it and/or modify
7dd0b342
  * 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
  *
6a0f4382
  * Kamailio is distributed in the hope that it will be useful,
7dd0b342
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
3881f12c
  */
 
1d0661db
 /*!
  * \file
6a0f4382
  * \brief Kamailio core :: Flags
1d0661db
  * \ingroup core
  * Module: \ref core
  */
 
7dd0b342
 
3881f12c
 #include <limits.h>
 #include "sr_module.h"
 #include "dprint.h"
 #include "parser/msg_parser.h"
 #include "flags.h"
 #include "error.h"
 #include "stdlib.h"
65938e0e
 #include "hashes.h"
e8138515
 #include "clist.h"
 #include "mem/mem.h"
3881f12c
 
7c770413
 /* Script flags */
 static flag_t sflags = 0;
 
 
3881f12c
 int setflag( struct sip_msg* msg, flag_t flag ) {
 	msg->flags |= 1 << flag;
 	return 1;
 }
 
 int resetflag( struct sip_msg* msg, flag_t flag ) {
caf80ae6
 	msg->flags &= ~ (1 << flag);
3881f12c
 	return 1;
 }
 
 int isflagset( struct sip_msg* msg, flag_t flag ) {
caf80ae6
 	return (msg->flags & (1<<flag)) ? 1 : -1;
3881f12c
 }
 
 int flag_in_range( flag_t flag ) {
 	if (flag > MAX_FLAG ) {
2990e54f
 		LM_ERR("message flag %d too high; MAX=%d\n", flag, MAX_FLAG );
3881f12c
 		return 0;
 	}
f0fb6f1e
 	if ((int)flag<0) {
2990e54f
 		LM_ERR("message flag (%d) must be in range 0..%d\n", flag, MAX_FLAG );
3881f12c
 		return 0;
 	}
 	return 1;
 }
 
 
7c770413
 int setsflagsval(flag_t val)
 {
 	sflags = val;
 	return 1;
 }
 
 
 int setsflag(flag_t flag)
 {
 	sflags |= 1 << flag;
 	return 1;
 }
 
 
 int resetsflag(flag_t flag)
 {
 	sflags &= ~ (1 << flag);
 	return 1;
 }
 
 
 int issflagset(flag_t flag)
 {
 	return (sflags & (1<<flag)) ? 1 : -1;
 }
 
 
 flag_t getsflags(void)
 {
 	return sflags;
 }
 
 
65938e0e
 /* use 2^k */
 #define FLAGS_NAME_HASH_ENTRIES		32
 
 struct flag_entry{
 	struct flag_entry* next;
 	struct flag_entry* prev;
7b6b4351
 	str name;
 	int no;
65938e0e
 };
 
 
 struct flag_hash_head{
 	struct flag_entry* next;
 	struct flag_entry* prev;
 };
 
 static struct flag_hash_head  name2flags[FLAGS_NAME_HASH_ENTRIES];
7b6b4351
 static unsigned char registered_flags[MAX_FLAG+1];
65938e0e
 
 
 void init_named_flags()
 {
 	int r;
 	
 	for (r=0; r<FLAGS_NAME_HASH_ENTRIES; r++)
 		clist_init(&name2flags[r], next, prev);
 }
 
 
 
 /* returns 0 on success, -1 on error */
 int check_flag(int n)
 {
 	if (!flag_in_range(n))
 		return -1;
 	if (registered_flags[n]){
2990e54f
 		LM_WARN("flag %d is already used by a named flag\n", n);
65938e0e
 	}
 	return 0;
 }
 
 
 inline static struct flag_entry* flag_search(struct flag_hash_head* lst,
 												char* name, int len)
 {
 	struct flag_entry* fe;
 	
 	clist_foreach(lst, fe, next){
 		if ((fe->name.len==len) && (memcmp(fe->name.s, name, len)==0)){
 			/* found */
 			return fe;
 		}
 	}
 	return 0;
 }
 
 
 
 /* returns flag entry or 0 on not found */
 inline static struct flag_entry* get_flag_entry(char* name, int len)
 {
 	int h;
 	/* get hash */
 	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
 	return flag_search(&name2flags[h], name, len);
 }
 
 
 
 /* returns flag number, or -1 on error */
 int get_flag_no(char* name, int len)
 {
 	struct flag_entry* fe;
 	
 	fe=get_flag_entry(name, len);
 	return (fe)?fe->no:-1;
 }
 
 
 
 /* resgiter a new flag name and associates it with pos
  * pos== -1 => any position will do 
  * returns flag pos on success (>=0)
  *         -1  flag is an alias for an already existing flag
  *         -2  flag already registered
  *         -3  mem. alloc. failure
  *         -4  invalid pos
  *         -5 no free flags */
 int register_flag(char* name, int pos)
 {
 	struct flag_entry* e;
 	int len;
 	unsigned int r;
 	static unsigned int crt_flag=0;
 	unsigned int last_flag;
 	unsigned int h;
 	
 	len=strlen(name);
 	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
 	/* check if the name already exists */
 	e=flag_search(&name2flags[h], name, len);
 	if (e){
2990e54f
 		LM_ERR("flag %.*s already registered\n", len, name);
65938e0e
 		return -2;
 	}
 	/* check if there is already another flag registered at pos */
 	if (pos!=-1){
 		if ((pos<0) || (pos>MAX_FLAG)){
2990e54f
 			LM_ERR("invalid flag %.*s position(%d)\n", len, name, pos);
65938e0e
 			return -4;
 		}
 		if (registered_flags[pos]!=0){
2990e54f
 			LM_WARN("%.*s:  flag %d already in use under another name\n",
 					len, name, pos);
65938e0e
 			/* continue */
 		}
 	}else{
 		/* alloc an empty flag */
7b6b4351
 		last_flag=crt_flag+(MAX_FLAG+1);
65938e0e
 		for (; crt_flag!=last_flag; crt_flag++){
7b6b4351
 			r=crt_flag%(MAX_FLAG+1);
65938e0e
 			if (registered_flags[r]==0){
 				pos=r;
 				break;
 			}
 		}
 		if (pos==-1){
2990e54f
 			LM_ERR("could not register %.*s - too many flags\n", len, name);
65938e0e
 			return -5;
 		}
 	}
 	registered_flags[pos]++;
 	
 	e=pkg_malloc(sizeof(struct flag_entry));
 	if (e==0){
2990e54f
 		LM_ERR("memory allocation failure\n");
65938e0e
 		return -3;
 	}
 	e->name.s=name;
 	e->name.len=len;
 	e->no=pos;
 	clist_insert(&name2flags[h], e, next, prev);
 	return pos;
 }
 
 
 
3881f12c
 #ifdef _GET_AWAY
 
 /* wrapping functions for flag processing  */
 static int fixup_t_flag(void** param, int param_no)
 {
     unsigned int *code;
 	char *c;
 	int token;
 
9f7dd69a
 	LM_DBG("fixing flag: %s\n", (char *) (*param));
3881f12c
 
 	if (param_no!=1) {
2990e54f
 		LM_ERR("TM module: only parameter #1 for flags can be fixed\n");
3881f12c
 		return E_BUG;
 	};
 
e3dccdc9
 	if ( !(code =pkg_malloc( sizeof( unsigned int) )) ) return E_OUT_OF_MEM;
3881f12c
 
 	*code = 0;
 	c = *param;
53c7e0f1
 	while ( *c && (*c==' ' || *c=='\t')) c++; /* initial whitespaces */
3881f12c
 
 	token=1;
 	if (strcasecmp(c, "white")==0) *code=FL_WHITE;
 	else if (strcasecmp(c, "yellow")==0) *code=FL_YELLOW;
 	else if (strcasecmp(c, "green")==0) *code=FL_GREEN;
 	else if (strcasecmp(c, "red")==0) *code=FL_RED;
 	else if (strcasecmp(c, "blue")==0) *code=FL_BLUE;
 	else if (strcasecmp(c, "magenta")==0) *code=FL_MAGENTA;
 	else if (strcasecmp(c, "brown")==0) *code=FL_BROWN;
 	else if (strcasecmp(c, "black")==0) *code=FL_BLACK;
 	else if (strcasecmp(c, "acc")==0) *code=FL_ACC;
 	else {
 		token=0;
 		while ( *c && *c>='0' && *c<='9' ) {
 			*code = *code*10+ *c-'0';
 			if (*code > (sizeof( flag_t ) * CHAR_BIT - 1 )) {
2990e54f
 				LM_ERR("TM module: too big flag number: %s; MAX=%d\n",
3881f12c
 					(char *) (*param), sizeof( flag_t ) * CHAR_BIT - 1 );
 				goto error;
 			}
 			c++;
 		}
 	}
 	while ( *c && (*c==' ' || *c=='\t')) c++; /* terminating whitespaces */
 
 	if ( *code == 0 ) {
2990e54f
 		LM_ERR("TM module: bad flag number: %s\n", (char *) (*param));
3881f12c
 		goto error;
 	}
 
 	if (*code < FL_MAX && token==0) {
2990e54f
 		LM_ERR("TM module: too high flag number: %s (%d)\n; lower number"
3881f12c
 			" bellow %d reserved\n", (char *) (*param), *code, FL_MAX );
 		goto error;
 	}
 
 	/* free string */
e3dccdc9
 	pkg_free( *param );
3881f12c
 	/* fix now */
 	*param = code;
 	
 	return 0;
 
 error:
e3dccdc9
 	pkg_free( code );
3881f12c
 	return E_CFG;
 }
 
 
 #endif