1 /*
2  * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
3  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
4  *
5  * This file is part of kamailio, a free SIP server.
6  *
7  * Kamailio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (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  * \file
24  * \brief Dialog variables
25  * \ingroup dialog
26  * Module: \ref dialog
27  */
28 
29 #include "../../core/route.h"
30 #include "../../core/script_cb.h"
31 #include "../../core/pvapi.h"
32 #include "../../core/counters.h"
33 
34 #include "dlg_var.h"
35 #include "dlg_hash.h"
36 #include "dlg_profile.h"
37 #include "dlg_handlers.h"
38 #include "dlg_db_handler.h"
39 
40 dlg_ctx_t _dlg_ctx;
41 extern int spiral_detected;
42 
43 /*! global variable table, in case the dialog does not exist yet */
44 static struct dlg_var *_dlg_var_table = 0;
45 /*! ID of the current message */
46 int msg_id;
47 
dlg_cfg_cb(sip_msg_t * msg,unsigned int flags,void * cbp)48 int dlg_cfg_cb(sip_msg_t *msg, unsigned int flags, void *cbp)
49 {
50 	dlg_cell_t *dlg;
51 	if(get_route_type()==LOCAL_ROUTE) {
52 		return 1;
53 	}
54 	if(flags&POST_SCRIPT_CB) {
55 		dlg = dlg_get_ctx_dialog();
56 		if(dlg!=NULL) {
57 			if(_dlg_ctx.t==0 && (dlg->state==DLG_STATE_UNCONFIRMED
58 						|| _dlg_ctx.expect_t==1)) {
59 				if(_dlg_ctx.cpid!=0 && _dlg_ctx.cpid==my_pid()) {
60 					/* release to destroy dialog if created by this process
61 					 * and request was not forwarded */
62 					if(dlg->state==DLG_STATE_UNCONFIRMED) {
63 						LM_DBG("new dialog with no transaction after config"
64 									" execution\n");
65 					} else {
66 						LM_DBG("dialog with no expected transaction after"
67 								" config execution\n");
68 					}
69 					dlg_release(dlg);
70 				}
71 			}
72 			/* get ctx dlg increased ref count - release now */
73 			dlg_release(dlg);
74 		}
75 	}
76 	memset(&_dlg_ctx, 0, sizeof(dlg_ctx_t));
77 
78 	return 1;
79 }
80 
cb_dlg_cfg_reset(sip_msg_t * msg,unsigned int flags,void * cbp)81 int cb_dlg_cfg_reset(sip_msg_t *msg, unsigned int flags, void *cbp)
82 {
83 	if(get_route_type()==LOCAL_ROUTE) {
84 		return 1;
85 	}
86 
87 	memset(&_dlg_ctx, 0, sizeof(dlg_ctx_t));
88 
89 	return 1;
90 }
91 
cb_dlg_locals_reset(sip_msg_t * msg,unsigned int flags,void * cbp)92 int cb_dlg_locals_reset(sip_msg_t *msg, unsigned int flags, void *cbp)
93 {
94 	if(get_route_type()==LOCAL_ROUTE) {
95 		return 1;
96 	}
97 	LM_DBG("resetting the local dialog shortcuts on script callback: %u\n", flags);
98 	cb_dlg_cfg_reset(msg, flags, cbp);
99 	cb_profile_reset(msg, flags, cbp);
100 
101 	return 1;
102 }
103 
new_dlg_var(str * key,str * val)104 static inline struct dlg_var *new_dlg_var(str *key, str *val)
105 {
106 	struct dlg_var *var;
107 
108 	var =(struct dlg_var*)shm_malloc(sizeof(struct dlg_var));
109 	if (var==NULL) {
110 		LM_ERR("no more shm mem\n");
111 		return NULL;
112 	}
113 	memset(var, 0, sizeof(struct dlg_var));
114 	var->vflags = DLG_FLAG_NEW;
115 	/* set key */
116 	var->key.len = key->len;
117 	var->key.s = (char*)shm_malloc(var->key.len+1);
118 	if (var->key.s==NULL) {
119 		shm_free(var);
120 		LM_ERR("no more shm mem\n");
121 		return NULL;
122 	}
123 	memcpy(var->key.s, key->s, key->len);
124 	var->key.s[var->key.len] = '\0';
125 	/* set value */
126 	var->value.len = val->len;
127 	var->value.s = (char*)shm_malloc(var->value.len+1);
128 	if (var->value.s==NULL) {
129 		shm_free(var->key.s);
130 		shm_free(var);
131 		LM_ERR("no more shm mem\n");
132 		return NULL;
133 	}
134 	memcpy(var->value.s, val->s, val->len);
135 	var->value.s[var->value.len] = '\0';
136 	return var;
137 }
138 
139 /*! Delete the current var-list */
free_local_varlist()140 void free_local_varlist() {
141 	struct dlg_var *var;
142 	while (_dlg_var_table) {
143 		var = _dlg_var_table;
144 		_dlg_var_table = _dlg_var_table->next;
145 		shm_free(var->key.s);
146 		shm_free(var->value.s);
147 		shm_free(var);
148 	}
149 	_dlg_var_table = NULL;
150 }
151 
152 /*! Retrieve the local var-list pointer */
get_local_varlist_pointer(struct sip_msg * msg,int clear_pointer)153 struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointer) {
154 	struct dlg_var *var;
155 	/* New list, delete the old one */
156 	if (msg->id != msg_id) {
157 		free_local_varlist();
158 		msg_id = msg->id;
159 	}
160 	var = _dlg_var_table;
161 	if (clear_pointer)
162 		_dlg_var_table = NULL;
163 	return var;
164 }
165 
166 /* Adds, updates and deletes dialog variables */
set_dlg_variable_unsafe(struct dlg_cell * dlg,str * key,str * val)167 int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val)
168 {
169 	struct dlg_var * var = NULL;
170 	struct dlg_var * it;
171 	struct dlg_var * it_prev;
172 	struct dlg_var ** var_list;
173 
174 	if (dlg)
175 		var_list = &dlg->vars;
176 	else
177 		var_list = &_dlg_var_table;
178 
179 	if ( val && (var=new_dlg_var(key, val))==NULL) {
180 		LM_ERR("failed to create new dialog variable\n");
181 		return -1;
182 	}
183 
184 	/* iterate the list */
185 	for( it_prev=NULL, it=*var_list ; it ; it_prev=it,it=it->next) {
186 		if (key->len==it->key.len && memcmp(key->s,it->key.s,key->len)==0
187 			&& (it->vflags & DLG_FLAG_DEL) == 0) {
188 			/* found -> replace or delete it */
189 			if (val==NULL) {
190 				/* delete it */
191 				if (it_prev) it_prev->next = it->next;
192 				else *var_list = it->next;
193 				/* Set the delete-flag for the current var: */
194 				it->vflags &= DLG_FLAG_DEL;
195 			} else {
196 				/* replace the current it with var and free the it */
197 				var->next = it->next;
198 				/* Take the previous vflags: */
199 				var->vflags = it->vflags | DLG_FLAG_CHANGED;
200 				if (it_prev) it_prev->next = var;
201 				else *var_list = var;
202 			}
203 
204 			/* Free this var: */
205 			shm_free(it->key.s);
206 			shm_free(it->value.s);
207 			shm_free(it);
208 			return 0;
209 		}
210 	}
211 
212 	/* not found: */
213 	if (!var) {
214 		LM_DBG("dialog variable <%.*s> does not exist in variable list\n", key->len, key->s);
215 		return 1;
216 	}
217 
218 	/* insert a new one at the beginning of the list */
219 	var->next = *var_list;
220 	*var_list = var;
221 
222 	return 0;
223 }
224 
get_dlg_variable_unsafe(struct dlg_cell * dlg,str * key)225 str * get_dlg_variable_unsafe(struct dlg_cell *dlg, str *key)
226 {
227 	struct dlg_var *var, *var_list;
228 
229 	if (dlg)
230 		var_list = dlg->vars;
231 	else
232 		var_list = _dlg_var_table;
233 
234 	/* iterate the list */
235 	for(var=var_list ; var ; var=var->next) {
236 		if (key->len==var->key.len && memcmp(key->s,var->key.s,key->len)==0
237 		&& (var->vflags & DLG_FLAG_DEL) == 0) {
238 			return &var->value;
239 		}
240 	}
241 
242 	return NULL;
243 }
244 
pv_parse_dialog_var_name(pv_spec_p sp,str * in)245 int pv_parse_dialog_var_name(pv_spec_p sp, str *in)
246 {
247 	if(in==NULL || in->s==NULL || sp==NULL)
248 		return -1;
249 
250 	sp->pvp.pvn.type = PV_NAME_INTSTR;
251 	sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
252 	sp->pvp.pvn.u.isname.name.s = *in;
253 
254 	return 0;
255 }
256 
257 /*! Internal debugging function: Prints the list of dialogs */
print_lists(struct dlg_cell * dlg)258 void print_lists(struct dlg_cell *dlg) {
259 	struct dlg_var *varlist;
260 	varlist = _dlg_var_table;
261 	LM_DBG("Internal var-list (%p):\n", varlist);
262 	while (varlist) {
263 		LM_DBG("%.*s=%.*s (flags %i)\n",
264 			varlist->key.len, varlist->key.s,
265 			varlist->value.len, varlist->value.s,
266 			varlist->vflags);
267 		varlist = varlist->next;
268 	}
269 	if (dlg) {
270 		varlist = dlg->vars;
271 		LM_DBG("Dialog var-list (%p):\n", varlist);
272 		while (varlist) {
273 			LM_DBG("%.*s=%.*s (flags %i)\n",
274 				varlist->key.len, varlist->key.s,
275 				varlist->value.len, varlist->value.s,
276 				varlist->vflags);
277 			varlist = varlist->next;
278 		}
279 	}
280 }
281 
get_dlg_variable(struct dlg_cell * dlg,str * key)282 str * get_dlg_variable(struct dlg_cell *dlg, str *key)
283 {
284     str* var = NULL;
285 
286     if( !dlg || !key || key->len > strlen(key->s))
287     {
288         LM_ERR("BUG - bad parameters\n");
289 
290         return NULL;
291     }
292 
293     dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
294     var = get_dlg_variable_unsafe( dlg, key);
295     dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
296 
297     return var;
298 }
299 
set_dlg_variable(struct dlg_cell * dlg,str * key,str * val)300 int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
301 {
302     int ret = -1;
303     if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s)))
304     {
305         LM_ERR("BUG - bad parameters\n");
306         return -1;
307     }
308 
309     dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
310 
311     ret = set_dlg_variable_unsafe(dlg, key, val);
312     if(ret!= 0)
313         goto done;
314 
315     dlg->dflags |= DLG_FLAG_CHANGED_VARS;
316     dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
317     if ( dlg_db_mode==DB_MODE_REALTIME )
318         update_dialog_dbinfo(dlg);
319 
320     print_lists(dlg);
321 
322     return 0;
323 
324 done:
325     dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
326     return ret;
327 }
328 
pv_get_dlg_variable(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)329 int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
330 {
331 	dlg_cell_t *dlg;
332 	str * value;
333 	str spv;
334 
335 	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
336 			|| param->pvn.u.isname.type!=AVP_NAME_STR
337 			|| param->pvn.u.isname.name.s.s==NULL) {
338 		LM_CRIT("BUG - bad parameters\n");
339 		return -1;
340 	}
341 
342 	/* Retrieve the dialog for current message */
343 	dlg=dlg_get_msg_dialog( msg);
344 
345 	if (dlg) {
346 		/* Lock the dialog */
347 		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
348 	} else {
349 		/* Verify the local list */
350 		get_local_varlist_pointer(msg, 0);
351 	}
352 
353 	/* dcm: todo - the value should be cloned for safe usage */
354 	value = get_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s);
355 
356 	spv.s = NULL;
357 	if(value) {
358 		spv.len = pv_get_buffer_size();
359 		if(spv.len<value->len+1) {
360 			LM_ERR("pv buffer too small (%d) - needed %d\n", spv.len, value->len);
361 		} else {
362 			spv.s = pv_get_buffer();
363 			strncpy(spv.s, value->s, value->len);
364 			spv.len = value->len;
365 			spv.s[spv.len] = '\0';
366 		}
367 	}
368 
369 	print_lists(dlg);
370 
371 	/* unlock dialog */
372 	if (dlg) {
373 		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
374 		dlg_release(dlg);
375 	}
376 
377 	if (spv.s)
378 		return pv_get_strval(msg, param, res, &spv);
379 
380 
381 	return pv_get_null(msg, param, res);
382 }
383 
pv_set_dlg_variable(struct sip_msg * msg,pv_param_t * param,int op,pv_value_t * val)384 int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
385 {
386 	dlg_cell_t *dlg = NULL;
387 	int ret = -1;
388 
389 	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
390 			|| param->pvn.u.isname.type!=AVP_NAME_STR
391 			|| param->pvn.u.isname.name.s.s==NULL ) {
392 		LM_CRIT("BUG - bad parameters\n");
393 		goto error;
394 	}
395 
396 	/* Retrieve the dialog for current message */
397 	dlg=dlg_get_msg_dialog( msg);
398 
399 	if (dlg) {
400 		/* Lock the dialog */
401 		dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
402 	} else {
403 		/* Verify the local list */
404 		get_local_varlist_pointer(msg, 0);
405 	}
406 
407 	if (val==NULL || val->flags&(PV_VAL_NONE|PV_VAL_NULL|PV_VAL_EMPTY)) {
408 		/* if NULL, remove the value */
409 		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, NULL);
410 		if(ret!= 0) {
411 			/* unlock dialog */
412 			if (dlg) {
413 				dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
414 				dlg_release(dlg);
415 			}
416 			return ret;
417 		}
418 	} else {
419 		/* if value, must be string */
420 		if ( !(val->flags&PV_VAL_STR)) {
421 			LM_ERR("non-string values are not supported\n");
422 			/* unlock dialog */
423 			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
424 			goto error;
425 		}
426 
427 		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, &val->rs);
428 		if(ret!= 0) {
429 			/* unlock dialog */
430 			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
431 			goto error;
432 		}
433 	}
434 	/* unlock dialog */
435 	if (dlg) {
436 		dlg->dflags |= DLG_FLAG_CHANGED_VARS;
437 		if ( dlg_db_mode==DB_MODE_REALTIME ) {
438 			/* dlg_lock() / dlg_unlock() are reentrant */
439 			update_dialog_dbinfo(dlg);
440 		}
441 		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
442 	}
443 	print_lists(dlg);
444 
445 	dlg_release(dlg);
446 	return 0;
447 error:
448 	dlg_release(dlg);
449 	return -1;
450 }
451 
pv_get_dlg_ctx(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)452 int pv_get_dlg_ctx(struct sip_msg *msg,  pv_param_t *param,
453 		pv_value_t *res)
454 {
455 	if(param==NULL)
456 		return -1;
457 	switch(param->pvn.u.isname.name.n)
458 	{
459 		case 1:
460 			return pv_get_uintval(msg, param, res,
461 					(unsigned int)_dlg_ctx.flags);
462 		case 2:
463 			return pv_get_uintval(msg, param, res,
464 					(unsigned int)_dlg_ctx.timeout);
465 		case 3:
466 			return pv_get_uintval(msg, param, res,
467 					(unsigned int)_dlg_ctx.to_bye);
468 		case 4:
469 			if(_dlg_ctx.to_route>0) {
470 				return pv_get_strzval(msg, param, res,
471 						_dlg_ctx.to_route_name);
472 			}
473 			return pv_get_null(msg, param, res);
474 		case 5:
475 			_dlg_ctx.set = (_dlg_ctx.iuid.h_id==0)?0:1;
476 			return pv_get_uintval(msg, param, res,
477 					(unsigned int)_dlg_ctx.set);
478 		case 6:
479 			return pv_get_uintval(msg, param, res,
480 					(unsigned int)_dlg_ctx.dir);
481 		case 7:
482 			return pv_get_sintval(msg, param, res,
483 					_dlg_ctx.to_route);
484 		default:
485 			return pv_get_uintval(msg, param, res,
486 					(unsigned int)_dlg_ctx.on);
487 	}
488 	return 0;
489 }
490 
pv_set_dlg_ctx(struct sip_msg * msg,pv_param_t * param,int op,pv_value_t * val)491 int pv_set_dlg_ctx(struct sip_msg* msg, pv_param_t *param,
492 		int op, pv_value_t *val)
493 {
494 	int n;
495 	int rlen;
496 	char *rtp;
497 
498 	if(param==NULL)
499 		return -1;
500 
501 	n = 0;
502 	if(val!=NULL && val->flags&PV_VAL_INT)
503 		n = val->ri;
504 
505 	switch(param->pvn.u.isname.name.n)
506 	{
507 		case 1:
508 			_dlg_ctx.flags = n;
509 		break;
510 		case 2:
511 			_dlg_ctx.timeout = n;
512 		break;
513 		case 3:
514 			_dlg_ctx.to_bye = n;
515 		break;
516 		case 4:
517 			if(val && val->flags&PV_VAL_STR) {
518 				if(val->rs.s[val->rs.len]=='\0'
519 						&& val->rs.len<DLG_TOROUTE_SIZE) {
520 					_dlg_ctx.to_route = route_lookup(&main_rt, val->rs.s);
521 					strcpy(_dlg_ctx.to_route_name, val->rs.s);
522 				} else { _dlg_ctx.to_route = 0; }
523 			} else {
524 				if(n!=0) {
525 					rtp = int2str(n, &rlen);
526 					if(rlen<DLG_TOROUTE_SIZE) {
527 						_dlg_ctx.to_route = route_lookup(&main_rt, rtp);
528 						strcpy(_dlg_ctx.to_route_name, rtp);
529 					} else { _dlg_ctx.to_route = 0; }
530 				} else { _dlg_ctx.to_route = 0; }
531 			}
532 			if(_dlg_ctx.to_route <0) _dlg_ctx.to_route = 0;
533 		break;
534 		default:
535 			_dlg_ctx.on = n;
536 		break;
537 	}
538 	return 0;
539 }
540 
pv_parse_dlg_ctx_name(pv_spec_p sp,str * in)541 int pv_parse_dlg_ctx_name(pv_spec_p sp, str *in)
542 {
543 	if(sp==NULL || in==NULL || in->len<=0)
544 		return -1;
545 
546 	switch(in->len)
547 	{
548 		case 2:
549 			if(strncmp(in->s, "on", 2)==0)
550 				sp->pvp.pvn.u.isname.name.n = 0;
551 			else goto error;
552 		break;
553 		case 3:
554 			if(strncmp(in->s, "set", 3)==0)
555 				sp->pvp.pvn.u.isname.name.n = 5;
556 			else if(strncmp(in->s, "dir", 3)==0)
557 				sp->pvp.pvn.u.isname.name.n = 6;
558 			else goto error;
559 		break;
560 		case 5:
561 			if(strncmp(in->s, "flags", 6)==0)
562 				sp->pvp.pvn.u.isname.name.n = 1;
563 			else goto error;
564 		break;
565 		case 7:
566 			if(strncmp(in->s, "timeout", 7)==0)
567 				sp->pvp.pvn.u.isname.name.n = 2;
568 			else goto error;
569 		break;
570 		case 11:
571 			if(strncmp(in->s, "timeout_bye", 11)==0)
572 				sp->pvp.pvn.u.isname.name.n = 3;
573 			else goto error;
574 		break;
575 		case 13:
576 			if(strncmp(in->s, "timeout_route", 13)==0)
577 				sp->pvp.pvn.u.isname.name.n = 4;
578 			else goto error;
579 		break;
580 		case 16:
581 			if(strncmp(in->s, "timeout_route_id", 16)==0)
582 				sp->pvp.pvn.u.isname.name.n = 7;
583 			else goto error;
584 		break;
585 		default:
586 			goto error;
587 	}
588 	sp->pvp.pvn.type = PV_NAME_INTSTR;
589 	sp->pvp.pvn.u.isname.type = 0;
590 
591 	return 0;
592 
593 error:
594 	LM_ERR("unknown PV name %.*s\n", in->len, in->s);
595 	return -1;
596 }
597 
pv_get_dlg(struct sip_msg * msg,pv_param_t * param,pv_value_t * res)598 int pv_get_dlg(struct sip_msg *msg, pv_param_t *param,
599 		pv_value_t *res)
600 {
601 	dlg_cell_t *dlg = NULL;
602 	int res_type = 0;
603 	str sv = { 0 };
604 	unsigned int ui = 0;
605 	int si = 0;
606 
607 	if(param==NULL)
608 		return -1;
609 
610 	if(_dlg_ctx.iuid.h_id==0)
611 	{
612 		/* Retrieve the dialog for current message */
613 		dlg=dlg_get_msg_dialog(msg);
614 	} else {
615 		/* Retrieve the dialog for current context */
616 		dlg=dlg_get_by_iuid(&_dlg_ctx.iuid);
617 	}
618 	if(dlg == NULL)
619 		return pv_get_null(msg, param, res);
620 
621 	switch(param->pvn.u.isname.name.n)
622 	{
623 		case 1:
624 			res_type = 1;
625 			ui = (unsigned int)dlg->h_id;
626 			break;
627 		case 2:
628 			res_type = 1;
629 			ui = (unsigned int)dlg->state;
630 			break;
631 		case 3:
632 			if(dlg->route_set[DLG_CALLEE_LEG].s==NULL
633 					|| dlg->route_set[DLG_CALLEE_LEG].len<=0)
634 				goto done;
635 			sv.s = pv_get_buffer();
636 			sv.len = dlg->route_set[DLG_CALLEE_LEG].len;
637 			if(pv_get_buffer_size()<sv.len)
638 				goto done;
639 			res_type = 2;
640 			strncpy(sv.s, dlg->route_set[DLG_CALLEE_LEG].s, sv.len);
641 			sv.s[sv.len] = '\0';
642 			break;
643 		case 4:
644 			res_type = 1;
645 			ui = (unsigned int)dlg->dflags;
646 			break;
647 		case 5:
648 			res_type = 1;
649 			ui = (unsigned int)dlg->sflags;
650 			break;
651 		case 6:
652 			if(dlg->callid.s==NULL
653 					|| dlg->callid.len<=0)
654 				goto done;
655 			sv.s = pv_get_buffer();
656 			sv.len = dlg->callid.len;
657 			if(pv_get_buffer_size()<sv.len)
658 				goto done;
659 			res_type = 2;
660 			strncpy(sv.s, dlg->callid.s, sv.len);
661 			sv.s[sv.len] = '\0';
662 			break;
663 		case 7:
664 			if(dlg->to_uri.s==NULL
665 					|| dlg->to_uri.len<=0)
666 				goto done;
667 			sv.s = pv_get_buffer();
668 			sv.len = dlg->to_uri.len;
669 			if(pv_get_buffer_size()<sv.len)
670 				goto done;
671 			res_type = 2;
672 			strncpy(sv.s, dlg->to_uri.s, sv.len);
673 			sv.s[sv.len] = '\0';
674 			break;
675 		case 8:
676 			if(dlg->tag[DLG_CALLEE_LEG].s==NULL
677 					|| dlg->tag[DLG_CALLEE_LEG].len<=0)
678 				goto done;
679 			sv.s = pv_get_buffer();
680 			sv.len = dlg->tag[DLG_CALLEE_LEG].len;
681 			if(pv_get_buffer_size()<sv.len)
682 				goto done;
683 			res_type = 2;
684 			strncpy(sv.s, dlg->tag[DLG_CALLEE_LEG].s, sv.len);
685 			sv.s[sv.len] = '\0';
686 			break;
687 		case 9:
688 			res_type = 3;
689 			si = dlg->toroute;
690 			break;
691 		case 10:
692 			if(dlg->cseq[DLG_CALLEE_LEG].s==NULL
693 					|| dlg->cseq[DLG_CALLEE_LEG].len<=0)
694 				goto done;
695 			sv.s = pv_get_buffer();
696 			sv.len = dlg->cseq[DLG_CALLEE_LEG].len;
697 			if(pv_get_buffer_size()<sv.len)
698 				goto done;
699 			res_type = 2;
700 			strncpy(sv.s, dlg->cseq[DLG_CALLEE_LEG].s, sv.len);
701 			sv.s[sv.len] = '\0';
702 			break;
703 		case 11:
704 			if(dlg->route_set[DLG_CALLER_LEG].s==NULL
705 					|| dlg->route_set[DLG_CALLER_LEG].len<=0)
706 				goto done;
707 			sv.s = pv_get_buffer();
708 			sv.len = dlg->route_set[DLG_CALLER_LEG].len;
709 			if(pv_get_buffer_size()<sv.len)
710 				goto done;
711 			res_type = 2;
712 			strncpy(sv.s, dlg->route_set[DLG_CALLER_LEG].s, sv.len);
713 			sv.s[sv.len] = '\0';
714 			break;
715 		case 12:
716 			if(dlg->from_uri.s==NULL
717 					|| dlg->from_uri.len<=0)
718 				goto done;
719 			sv.s = pv_get_buffer();
720 			sv.len = dlg->from_uri.len;
721 			if(pv_get_buffer_size()<sv.len)
722 				goto done;
723 			res_type = 2;
724 			strncpy(sv.s, dlg->from_uri.s, sv.len);
725 			sv.s[sv.len] = '\0';
726 			break;
727 		case 13:
728 			if(dlg->tag[DLG_CALLER_LEG].s==NULL
729 					|| dlg->tag[DLG_CALLER_LEG].len<=0)
730 				goto done;
731 			sv.s = pv_get_buffer();
732 			sv.len = dlg->tag[DLG_CALLER_LEG].len;
733 			if(pv_get_buffer_size()<sv.len)
734 				goto done;
735 			res_type = 2;
736 			strncpy(sv.s, dlg->tag[DLG_CALLER_LEG].s, sv.len);
737 			sv.s[sv.len] = '\0';
738 			break;
739 		case 14:
740 			res_type = 1;
741 			ui = (unsigned int)dlg->lifetime;
742 			break;
743 		case 15:
744 			res_type = 1;
745 			ui = (unsigned int)dlg->start_ts;
746 			break;
747 		case 16:
748 			if(dlg->cseq[DLG_CALLER_LEG].s==NULL
749 					|| dlg->cseq[DLG_CALLER_LEG].len<=0)
750 				goto done;
751 			sv.s = pv_get_buffer();
752 			sv.len = dlg->cseq[DLG_CALLER_LEG].len;
753 			if(pv_get_buffer_size()<sv.len)
754 				goto done;
755 			res_type = 2;
756 			strncpy(sv.s, dlg->cseq[DLG_CALLER_LEG].s, sv.len);
757 			sv.s[sv.len] = '\0';
758 			break;
759 		case 17:
760 			if(dlg->contact[DLG_CALLEE_LEG].s==NULL
761 					|| dlg->contact[DLG_CALLEE_LEG].len<=0)
762 				goto done;
763 			sv.s = pv_get_buffer();
764 			sv.len = dlg->contact[DLG_CALLEE_LEG].len;
765 			if(pv_get_buffer_size()<sv.len)
766 				goto done;
767 			res_type = 2;
768 			strncpy(sv.s, dlg->contact[DLG_CALLEE_LEG].s, sv.len);
769 			sv.s[sv.len] = '\0';
770 			break;
771 		case 18:
772 			if(dlg->bind_addr[DLG_CALLEE_LEG]==NULL)
773 				goto done;
774 			sv.s = pv_get_buffer();
775 			sv.len = dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len;
776 			if(pv_get_buffer_size()<sv.len)
777 				goto done;
778 			res_type = 2;
779 			strncpy(sv.s, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s, sv.len);
780 			sv.s[sv.len] = '\0';
781 			break;
782 		case 19:
783 			if(dlg->contact[DLG_CALLER_LEG].s==NULL
784 					|| dlg->contact[DLG_CALLER_LEG].len<=0)
785 				goto done;
786 			sv.s = pv_get_buffer();
787 			sv.len = dlg->contact[DLG_CALLER_LEG].len;
788 			if(pv_get_buffer_size()<sv.len)
789 				goto done;
790 			res_type = 2;
791 			strncpy(sv.s, dlg->contact[DLG_CALLER_LEG].s, sv.len);
792 			sv.s[sv.len] = '\0';
793 			break;
794 		case 20:
795 			if(dlg->bind_addr[DLG_CALLER_LEG]==NULL)
796 				goto done;
797 			sv.s = pv_get_buffer();
798 			sv.len = dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len;
799 			if(pv_get_buffer_size()<sv.len)
800 				goto done;
801 			res_type = 2;
802 			strncpy(sv.s, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s, sv.len);
803 			sv.s[sv.len] = '\0';
804 			break;
805 		case 21:
806 			res_type = 1;
807 			ui = (unsigned int)dlg->h_entry;
808 			break;
809 		default:
810 			res_type = 1;
811 			ui = (unsigned int)dlg->ref;
812 	}
813 
814 done:
815 	dlg_release(dlg);
816 
817 	switch(res_type) {
818 		case 1:
819 			return pv_get_uintval(msg, param, res, ui);
820 		case 2:
821 			return pv_get_strval(msg, param, res, &sv);
822 		case 3:
823 			return pv_get_sintval(msg, param, res, si);
824 		default:
825 			return pv_get_null(msg, param, res);
826 	}
827 }
828 
pv_parse_dlg_name(pv_spec_p sp,str * in)829 int pv_parse_dlg_name(pv_spec_p sp, str *in)
830 {
831 	if(sp==NULL || in==NULL || in->len<=0)
832 		return -1;
833 
834 	switch(in->len)
835 	{
836 		case 3:
837 			if(strncmp(in->s, "ref", 3)==0)
838 				sp->pvp.pvn.u.isname.name.n = 0;
839 			else goto error;
840 		break;
841 		case 4:
842 			if(strncmp(in->s, "h_id", 4)==0)
843 				sp->pvp.pvn.u.isname.name.n = 1;
844 			else goto error;
845 		break;
846 		case 5:
847 			if(strncmp(in->s, "state", 5)==0)
848 				sp->pvp.pvn.u.isname.name.n = 2;
849 			else if(strncmp(in->s, "to_rs", 5)==0)
850 				sp->pvp.pvn.u.isname.name.n = 3;
851 			else goto error;
852 		break;
853 		case 6:
854 			if(strncmp(in->s, "dflags", 6)==0)
855 				sp->pvp.pvn.u.isname.name.n = 4;
856 			else if(strncmp(in->s, "sflags", 6)==0)
857 				sp->pvp.pvn.u.isname.name.n = 5;
858 			else if(strncmp(in->s, "callid", 6)==0)
859 				sp->pvp.pvn.u.isname.name.n = 6;
860 			else if(strncmp(in->s, "to_uri", 6)==0)
861 				sp->pvp.pvn.u.isname.name.n = 7;
862 			else if(strncmp(in->s, "to_tag", 6)==0)
863 				sp->pvp.pvn.u.isname.name.n = 8;
864 			else goto error;
865 		break;
866 		case 7:
867 			if(strncmp(in->s, "toroute", 7)==0)
868 				sp->pvp.pvn.u.isname.name.n = 9;
869 			else if(strncmp(in->s, "to_cseq", 7)==0)
870 				sp->pvp.pvn.u.isname.name.n = 10;
871 			else if(strncmp(in->s, "from_rs", 7)==0)
872 				sp->pvp.pvn.u.isname.name.n = 11;
873 			else if(strncmp(in->s, "h_entry", 7)==0)
874 				sp->pvp.pvn.u.isname.name.n = 21;
875 			else goto error;
876 		break;
877 		case 8:
878 			if(strncmp(in->s, "from_uri", 8)==0)
879 				sp->pvp.pvn.u.isname.name.n = 12;
880 			else if(strncmp(in->s, "from_tag", 8)==0)
881 				sp->pvp.pvn.u.isname.name.n = 13;
882 			else if(strncmp(in->s, "lifetime", 8)==0)
883 				sp->pvp.pvn.u.isname.name.n = 14;
884 			else if(strncmp(in->s, "start_ts", 8)==0)
885 				sp->pvp.pvn.u.isname.name.n = 15;
886 			else goto error;
887 		break;
888 		case 9:
889 			if(strncmp(in->s, "from_cseq", 9)==0)
890 				sp->pvp.pvn.u.isname.name.n = 16;
891 			else goto error;
892 		break;
893 		case 10:
894 			if(strncmp(in->s, "to_contact", 10)==0)
895 				sp->pvp.pvn.u.isname.name.n = 17;
896 			else goto error;
897 		break;
898 		case 11:
899 			if(strncmp(in->s, "to_bindaddr", 11)==0)
900 				sp->pvp.pvn.u.isname.name.n = 18;
901 			else goto error;
902 		break;
903 		case 12:
904 			if(strncmp(in->s, "from_contact", 12)==0)
905 				sp->pvp.pvn.u.isname.name.n = 19;
906 			else goto error;
907 		break;
908 		case 13:
909 			if(strncmp(in->s, "from_bindaddr", 13)==0)
910 				sp->pvp.pvn.u.isname.name.n = 20;
911 			else goto error;
912 		break;
913 		default:
914 			goto error;
915 	}
916 	sp->pvp.pvn.type = PV_NAME_INTSTR;
917 	sp->pvp.pvn.u.isname.type = 0;
918 
919 	return 0;
920 
921 error:
922 	LM_ERR("unknown PV name %.*s\n", in->len, in->s);
923 	return -1;
924 }
925 
dlg_set_ctx_iuid(dlg_cell_t * dlg)926 void dlg_set_ctx_iuid(dlg_cell_t *dlg)
927 {
928 	_dlg_ctx.iuid.h_entry = dlg->h_entry;
929 	_dlg_ctx.iuid.h_id = dlg->h_id;
930 }
931 
dlg_reset_ctx_iuid(void)932 void dlg_reset_ctx_iuid(void)
933 {
934 	_dlg_ctx.iuid.h_entry = 0;
935 	_dlg_ctx.iuid.h_id = 0;
936 }
937 
dlg_get_ctx_dialog(void)938 dlg_cell_t* dlg_get_ctx_dialog(void)
939 {
940 	return dlg_get_by_iuid(&_dlg_ctx.iuid);
941 }
942 
dlg_get_dlg_ctx(void)943 dlg_ctx_t* dlg_get_dlg_ctx(void)
944 {
945 	return &_dlg_ctx;
946 }
947 
spiral_detect_reset(struct sip_msg * foo,unsigned int flags,void * bar)948 int spiral_detect_reset(struct sip_msg *foo, unsigned int flags, void *bar)
949 {
950 	if(get_route_type()==LOCAL_ROUTE) {
951 		return 1;
952 	}
953 	spiral_detected = -1;
954 
955 	return 0;
956 }
957