1 /*
2  * Copyright (C) 2004-2006 Voice Sistem SRL
3  * Copyright (C) 2008 Juha Heinanen
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * Kamailio is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * Kamailio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *
21  *
22  */
23 
24 /*! \file
25  * \ingroup acc
26  * \brief Acc:: Extra attributes
27  *
28  * - Module: \ref acc
29  */
30 
31 
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "../../core/dprint.h"
37 #include "../../core/ut.h"
38 #include "../../core/usr_avp.h"
39 #include "../../core/mem/mem.h"
40 #include "acc_api.h"
41 #include "acc_extra.h"
42 
43 #define EQUAL '='
44 #define SEPARATOR ';'
45 
46 
47 #if MAX_ACC_EXTRA<MAX_ACC_LEG
48 #define MAX_ACC_INT_BUF MAX_ACC_LEG
49 #else
50 #define MAX_ACC_INT_BUF MAX_ACC_EXTRA
51 #endif
52 /* here we copy the strings returned by int2str (which uses a static buffer) */
53 static char int_buf[INT2STR_MAX_LEN*MAX_ACC_INT_BUF];
54 
parse_acc_leg(char * extra_str)55 struct acc_extra *parse_acc_leg(char *extra_str)
56 {
57 	struct acc_extra *legs;
58 	struct acc_extra *it;
59 	int n;
60 
61 	legs = parse_acc_extra(extra_str);
62 	if (legs==0) {
63 		LM_ERR("failed to parse extra leg\n");
64 		return 0;
65 	}
66 
67 	/* check the type and len */
68 	for( it=legs,n=0 ; it ; it=it->next ) {
69 		if (it->spec.type!=PVT_AVP) {
70 			LM_ERR("only AVP are accepted as leg info\n");
71 			destroy_extras(legs);
72 			return 0;
73 		}
74 		n++;
75 		if (n>MAX_ACC_LEG) {
76 			LM_ERR("too many leg info; MAX=%d\n", MAX_ACC_LEG);
77 			destroy_extras(legs);
78 			return 0;
79 		}
80 	}
81 
82 	return legs;
83 }
84 
85 
parse_acc_extra(char * extra_str)86 struct acc_extra *parse_acc_extra(char *extra_str)
87 {
88 	struct acc_extra *head;
89 	struct acc_extra *tail;
90 	struct acc_extra *extra;
91 	char *foo;
92 	char *s;
93 	int  n;
94 	str stmp;
95 
96 	n = 0;
97 	head = 0;
98 	extra = 0;
99 	tail = 0;
100 	s = extra_str;
101 
102 	if (s==0) {
103 		LM_ERR("null string received\n");
104 		goto error;
105 	}
106 
107 	while (*s) {
108 		/* skip white spaces */
109 		while (*s && isspace((int)*s))  s++;
110 		if (*s==0)
111 			goto parse_error;
112 		if (n==MAX_ACC_EXTRA) {
113 			LM_ERR("too many extras -> please increase the internal buffer\n");
114 			goto error;
115 		}
116 		extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra));
117 		if (extra==0) {
118 			PKG_MEM_ERROR;
119 			goto error;
120 		}
121 		memset( extra, 0, sizeof(struct acc_extra));
122 
123 		/* link the new extra at the end */
124 		if (tail==0) {
125 			head = extra;
126 		} else {
127 			tail->next = extra;
128 		}
129 		tail = extra;
130 		n++;
131 
132 		/* get name */
133 		foo = s;
134 		while (*s && !isspace((int)*s) && EQUAL!=*s)  s++;
135 		if (*s==0)
136 			goto parse_error;
137 		if (*s==EQUAL) {
138 			extra->name.len = (s++) - foo;
139 		} else {
140 			extra->name.len = (s++) - foo;
141 			/* skip spaces */
142 			while (*s && isspace((int)*s))  s++;
143 			if (*s!=EQUAL)
144 				goto parse_error;
145 			s++;
146 		}
147 		extra->name.s = foo;
148 
149 		/* skip spaces */
150 		while (*s && isspace((int)*s))  s++;
151 
152 		/* get value type */
153 		stmp.s = s; stmp.len = strlen(s);
154 		if ( (foo=pv_parse_spec(&stmp, &extra->spec))==0 )
155 			goto parse_error;
156 		s = foo;
157 
158 		/* skip spaces */
159 		while (*s && isspace((int)*s))  s++;
160 		if (*s && (*(s++)!=SEPARATOR || *s==0))
161 			goto parse_error;
162 	}
163 
164 	/* go throught all extras and make the names null terminated */
165 	for( extra=head ; extra ; extra=extra->next)
166 		extra->name.s[extra->name.len] = 0;
167 
168 	return head;
169 parse_error:
170 	LM_ERR("parse failed in <%s> "
171 			"around position %d\n",extra_str, (int)(long)(s-extra_str));
172 error:
173 	LM_ERR("error\n");
174 	destroy_extras(head);
175 	return 0;
176 }
177 
178 
179 
destroy_extras(struct acc_extra * extra)180 void destroy_extras( struct acc_extra *extra)
181 {
182 	struct acc_extra *foo;
183 
184 	while (extra) {
185 		foo = extra;
186 		extra = extra->next;
187 		pkg_free(foo);
188 	}
189 }
190 
191 
192 /*! \brief converts the name of the extra from str to integer
193  * and stores it over str.len ; str.s is freed and made zero
194  */
extra2int(struct acc_extra * extra,int * attrs)195 int extra2int( struct acc_extra *extra, int *attrs )
196 {
197 	unsigned int ui;
198 	int i;
199 
200 	for( i=0 ; extra ; i++,extra=extra->next ) {
201 		if (str2int( &extra->name, &ui)!=0) {
202 			LM_ERR("<%s> is not a number\n", extra->name.s);
203 			return -1;
204 		}
205 		attrs[i] = (int)ui;
206 	}
207 	return i;
208 }
209 
extra2strar(struct acc_extra * extra,struct sip_msg * rq,str * val_arr,int * int_arr,char * type_arr)210 int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
211 		int *int_arr, char *type_arr)
212 {
213 	pv_value_t value;
214 	int n;
215 	int i;
216 
217 	n = 0;
218 	i = 0;
219 
220 	while (extra) {
221 		/* get the value */
222 		if (pv_get_spec_value( rq, &extra->spec, &value)!=0) {
223 			LM_ERR("failed to get '%.*s'\n", extra->name.len,extra->name.s);
224 		}
225 
226 		/* check for overflow */
227 		if (n==MAX_ACC_EXTRA) {
228 			LM_WARN("array to short -> omitting extras for accounting\n");
229 			goto done;
230 		}
231 
232 		if(value.flags&PV_VAL_NULL) {
233 			/* convert <null> to empty to have consistency */
234 			val_arr[n].s = 0;
235 			val_arr[n].len = 0;
236 			type_arr[n] = TYPE_NULL;
237 		} else {
238 			val_arr[n].s = (char *)pkg_malloc(value.rs.len);
239 			if (val_arr[n].s == NULL ) {
240 				PKG_MEM_ERROR;
241 				/* Cleanup already allocated memory and
242 				 * return that we didn't do anything */
243 				for (i = 0; i < n ; i++) {
244 					if (NULL != val_arr[i].s){
245 						pkg_free(val_arr[i].s);
246 						val_arr[i].s = NULL;
247 					}
248 				}
249 				n = 0;
250 				goto done;
251 			}
252 			memcpy(val_arr[n].s, value.rs.s, value.rs.len);
253 			val_arr[n].len = value.rs.len;
254 			if (value.flags&PV_VAL_INT) {
255 				int_arr[n] = value.ri;
256 				type_arr[n] = TYPE_INT;
257 			} else {
258 				type_arr[n] = TYPE_STR;
259 			}
260 		}
261 		n++;
262 
263 		extra = extra->next;
264 	}
265 
266 done:
267 	return n;
268 }
269 
extra2strar_dlg_only(struct acc_extra * extra,struct dlg_cell * dlg,str * val_arr,int * int_arr,char * type_arr,const struct dlg_binds * p_dlgb)270 int extra2strar_dlg_only(struct acc_extra *extra, struct dlg_cell* dlg, str *val_arr,
271 		int *int_arr, char *type_arr, const struct dlg_binds* p_dlgb)
272 {
273 	//string value;
274 	str* value = 0;
275 	int n=0;
276 
277 	if( !dlg || !val_arr || !int_arr || !type_arr || !p_dlgb)
278 	{
279 		LM_ERR( "invalid input parameter!\n");
280 		return 0;
281 	}
282 
283 	while (extra) {
284 
285 		/* check for overflow */
286 		if (n==MAX_ACC_EXTRA) {
287 			LM_WARN("array to short -> omitting extras for accounting\n");
288 			goto done;
289 		}
290 
291 		val_arr[n].s = 0;
292 		val_arr[n].len = 0;
293 		type_arr[n] = TYPE_NULL;
294 
295 		str key = extra->spec.pvp.pvn.u.isname.name.s;
296 		if ( key.len == 0 || !key.s)
297 		{
298 			n++; extra = extra->next; continue;
299 		}
300 		/* get the value */
301 		value = p_dlgb->get_dlg_var( dlg, &key);
302 
303 		if (value)
304 		{
305 			val_arr[n].s = value->s;
306 			val_arr[n].len = value->len;
307 			type_arr[n] = TYPE_STR;
308 		}
309 
310 		n++;
311 		extra = extra->next;
312 	}
313 done:
314 	return n;
315 }
316 
legs2strar(struct acc_extra * legs,struct sip_msg * rq,str * val_arr,int * int_arr,char * type_arr,int start)317 int legs2strar( struct acc_extra *legs, struct sip_msg *rq, str *val_arr,
318 		int *int_arr, char *type_arr, int start)
319 {
320 	static struct usr_avp *avp[MAX_ACC_LEG];
321 	static struct search_state st[MAX_ACC_LEG];
322 	unsigned short name_type;
323 	int_str name;
324 	int_str value;
325 	int    n;
326 	int    found;
327 	int    r;
328 
329 	found = 0;
330 	r = 0;
331 
332 	for( n=0 ; legs ; legs=legs->next,n++ ) {
333 		/* search for the AVP */
334 		if (start) {
335 			if ( pv_get_avp_name( rq, &(legs->spec.pvp), &name, &name_type)<0 )
336 				goto exit;
337 			avp[n] = search_first_avp( name_type, name, &value, st + n);
338 		} else {
339 			avp[n] = search_next_avp(st + n, &value);
340 		}
341 
342 		/* set new leg record */
343 		if (avp[n]) {
344 			found = 1;
345 			/* get its value */
346 			if(avp[n]->flags & AVP_VAL_STR) {
347 				val_arr[n] = value.s;
348 				type_arr[n] = TYPE_STR;
349 			} else {
350 				val_arr[n].s = int2bstr( value.n, int_buf+r*INT2STR_MAX_LEN,
351 						&val_arr[n].len);
352 				r++;
353 				int_arr[n] = value.n;
354 				type_arr[n] = TYPE_INT;
355 			}
356 		} else {
357 			val_arr[n].s = 0;
358 			val_arr[n].len = 0;
359 			type_arr[n] = TYPE_NULL;
360 		}
361 
362 	}
363 
364 	if (found || start)
365 		return n;
366 exit:
367 	return 0;
368 }
369