1 /*
2  * pua_dialoginfo module - publish dialog-info from dialo module
3  *
4  * Copyright (C) 2006 Voice Sistem S.R.L.
5  * Copyright (C) 2007-2008 Dan Pascu
6  * Copyright (C) 2008 Klaus Darilion IPCom
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <libxml/parser.h>
30 #include <time.h>
31 
32 #include "../../core/script_cb.h"
33 #include "../../core/sr_module.h"
34 #include "../../core/parser/parse_expires.h"
35 #include "../../core/dprint.h"
36 #include "../../core/mem/shm_mem.h"
37 #include "../../core/parser/msg_parser.h"
38 #include "../../core/parser/parse_to.h"
39 #include "../../core/parser/contact/parse_contact.h"
40 #include "../../core/str.h"
41 #include "../../core/str_list.h"
42 #include "../../core/mem/mem.h"
43 #include "../../core/pt.h"
44 #include "../dialog/dlg_load.h"
45 #include "../dialog/dlg_hash.h"
46 #include "../pua/pua_bind.h"
47 #include "pua_dialoginfo.h"
48 
49 MODULE_VERSION
50 
51 /* Default module parameter values */
52 #define DEF_INCLUDE_CALLID 1
53 #define DEF_INCLUDE_LOCALREMOTE 1
54 #define DEF_INCLUDE_TAGS 1
55 #define DEF_OVERRIDE_LIFETIME 0
56 #define DEF_CALLER_ALWAYS_CONFIRMED 0
57 #define DEF_INCLUDE_REQ_URI 0
58 #define DEF_OVERRIDE_LIFETIME 0
59 #define DEF_SEND_PUBLISH_FLAG -1
60 #define DEF_USE_PUBRURI_AVPS 0
61 #define DEF_PUBRURI_CALLER_AVP 0
62 #define DEF_PUBRURI_CALLEE_AVP 0
63 #define DEF_CALLEE_TRYING 0
64 #define DEF_DISABLE_CALLER_PUBLISH_FLAG -1
65 #define DEF_DISABLE_CALLEE_PUBLISH_FLAG -1
66 
67 /* define PUA_DIALOGINFO_DEBUG to activate more verbose
68  * logging and dialog info callback debugging
69  */
70 /* #define PUA_DIALOGINFO_DEBUG 1 */
71 
72 pua_api_t pua;
73 
74 struct dlg_binds dlg_api;
75 
76 unsigned short pubruri_caller_avp_type;
77 int_str pubruri_caller_avp_name;
78 unsigned short pubruri_callee_avp_type;
79 int_str pubruri_callee_avp_name;
80 
81 static str caller_dlg_var = {0, 0}; /* pubruri_caller */
82 static str callee_dlg_var = {0, 0}; /* pubruri_callee */
83 
84 /* Module parameter variables */
85 int include_callid         = DEF_INCLUDE_CALLID;
86 int include_localremote    = DEF_INCLUDE_LOCALREMOTE;
87 int include_tags           = DEF_INCLUDE_TAGS;
88 int override_lifetime      = DEF_OVERRIDE_LIFETIME;
89 int caller_confirmed       = DEF_CALLER_ALWAYS_CONFIRMED;
90 int include_req_uri        = DEF_INCLUDE_REQ_URI;
91 int send_publish_flag      = DEF_SEND_PUBLISH_FLAG;
92 int use_pubruri_avps       = DEF_USE_PUBRURI_AVPS;
93 int callee_trying          = DEF_CALLEE_TRYING;
94 int disable_caller_publish_flag = DEF_DISABLE_CALLER_PUBLISH_FLAG;
95 int disable_callee_publish_flag = DEF_DISABLE_CALLEE_PUBLISH_FLAG;
96 char * pubruri_caller_avp  = DEF_PUBRURI_CALLER_AVP;
97 char * pubruri_callee_avp  = DEF_PUBRURI_CALLEE_AVP;
98 
99 
100 send_publish_t pua_send_publish;
101 /** module functions */
102 
103 static int mod_init(void);
104 
105 
106 static cmd_export_t cmds[]={
107 	{0, 0, 0, 0, 0, 0}
108 };
109 
110 static param_export_t params[]={
111 	{"include_callid",      INT_PARAM, &include_callid },
112 	{"include_localremote", INT_PARAM, &include_localremote },
113 	{"include_tags",        INT_PARAM, &include_tags },
114 	{"override_lifetime",   INT_PARAM, &override_lifetime },
115 	{"caller_confirmed",    INT_PARAM, &caller_confirmed },
116 	{"include_req_uri",     INT_PARAM, &include_req_uri },
117 	{"send_publish_flag",   INT_PARAM, &send_publish_flag },
118 	{"use_pubruri_avps",    INT_PARAM, &use_pubruri_avps },
119 	{"pubruri_caller_avp",  PARAM_STRING, &pubruri_caller_avp },
120 	{"pubruri_callee_avp",  PARAM_STRING, &pubruri_callee_avp },
121 	{"pubruri_caller_dlg_var",  PARAM_STR, &caller_dlg_var },
122 	{"pubruri_callee_dlg_var",  PARAM_STR, &callee_dlg_var },
123 	{"callee_trying",       INT_PARAM, &callee_trying },
124 	{"disable_caller_publish_flag",   INT_PARAM, &disable_caller_publish_flag },
125 	{"disable_callee_publish_flag",   INT_PARAM, &disable_callee_publish_flag },
126 	{0, 0, 0 }
127 };
128 
129 struct module_exports exports= {
130 	"pua_dialoginfo",	/* module name */
131 	DEFAULT_DLFLAGS,	/* dlopen flags */
132 	cmds,				/* exported functions */
133 	params,				/* exported parameters */
134 	0,					/* RPC method exports */
135 	0,					/* exported pseudo-variables */
136 	0,					/* response handling function */
137 	mod_init,			/* module initialization function */
138 	0,					/* per-child init function */
139 	0					/* module destroy function */
140 };
141 
142 
143 #ifdef PUA_DIALOGINFO_DEBUG
144 static void
__dialog_cbtest(struct dlg_cell * dlg,int type,struct dlg_cb_params * _params)145 __dialog_cbtest(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
146 {
147 	str tag;
148 	struct sip_msg *msg;
149 	LM_ERR("dialog callback received, from=%.*s, to=%.*s\n",
150 			dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len,
151 			dlg->to_uri.s);
152 	if (dlg->tag[0].len && dlg->tag[0].s ) {
153 		LM_ERR("dialog callback: tag[0] = %.*s",
154 				dlg->tag[0].len, dlg->tag[0].s);
155 	}
156 	if (dlg->tag[0].len && dlg->tag[1].s ) {
157 		LM_ERR("dialog callback: tag[1] = %.*s",
158 				dlg->tag[1].len, dlg->tag[1].s);
159 	}
160 
161 	if (type != DLGCB_DESTROY) {
162 		msg = dlg_get_valid_msg(_params);
163 		if (!msg) {
164 			LM_ERR("no SIP message available in callback parameters\n");
165 			return;
166 		}
167 
168 		/* get to tag*/
169 		if ( !msg->to) {
170 			// to header not defined, parse to header
171 			LM_ERR("to header not defined, parse to header\n");
172 			if (parse_headers(msg, HDR_TO_F,0)<0) {
173 				//parser error
174 				LM_ERR("parsing of to-header failed\n");
175 				tag.s = 0;
176 				tag.len = 0;
177 			} else if (!msg->to) {
178 				// to header still not defined
179 				LM_ERR("bad reply or missing TO header\n");
180 				tag.s = 0;
181 				tag.len = 0;
182 			} else {
183 				tag = get_to(msg)->tag_value;
184 			}
185 		} else {
186 			tag = get_to(msg)->tag_value;
187 			if (tag.s==0 || tag.len==0) {
188 				LM_ERR("missing TAG param in TO hdr :-/\n");
189 				tag.s = 0;
190 				tag.len = 0;
191 			}
192 		}
193 		if (tag.s) {
194 			LM_ERR("dialog callback: msg->to->parsed->tag_value = %.*s",
195 					tag.len, tag.s);
196 		}
197 	}
198 
199 	switch (type) {
200 		case DLGCB_FAILED:
201 			LM_ERR("dialog callback type 'DLGCB_FAILED' received, from=%.*s\n",
202 					dlg->from_uri.len, dlg->from_uri.s);
203 			break;
204 		case DLGCB_CONFIRMED_NA:
205 			LM_ERR("dialog callback type 'DLGCB_CONFIRMED_NA' received, from=%.*s\n",
206 					dlg->from_uri.len, dlg->from_uri.s);
207 			break;
208 		case DLGCB_CONFIRMED:
209 			LM_ERR("dialog callback type 'DLGCB_CONFIRMED' received, from=%.*s\n",
210 					dlg->from_uri.len, dlg->from_uri.s);
211 			break;
212 		case DLGCB_REQ_WITHIN:
213 			LM_ERR("dialog callback type 'DLGCB_REQ_WITHIN' received, from=%.*s\n",
214 					dlg->from_uri.len, dlg->from_uri.s);
215 			break;
216 		case DLGCB_TERMINATED:
217 			LM_ERR("dialog callback type 'DLGCB_TERMINATED' received, from=%.*s\n",
218 					dlg->from_uri.len, dlg->from_uri.s);
219 			break;
220 		case DLGCB_EXPIRED:
221 			LM_ERR("dialog callback type 'DLGCB_EXPIRED' received, from=%.*s\n",
222 					dlg->from_uri.len, dlg->from_uri.s);
223 			break;
224 		case DLGCB_EARLY:
225 			LM_ERR("dialog callback type 'DLGCB_EARLY' received, from=%.*s\n",
226 					dlg->from_uri.len, dlg->from_uri.s);
227 			break;
228 		case DLGCB_RESPONSE_FWDED:
229 			LM_ERR("dialog callback type 'DLGCB_RESPONSE_FWDED' received, from=%.*s\n",
230 					dlg->from_uri.len, dlg->from_uri.s);
231 			break;
232 		case DLGCB_RESPONSE_WITHIN:
233 			LM_ERR("dialog callback type 'DLGCB_RESPONSE_WITHIN' received, from=%.*s\n",
234 					dlg->from_uri.len, dlg->from_uri.s);
235 			break;
236 		case DLGCB_DESTROY:
237 			LM_ERR("dialog callback type 'DLGCB_DESTROY' received, from=%.*s\n",
238 					dlg->from_uri.len, dlg->from_uri.s);
239 			break;
240 		default:
241 			LM_ERR("dialog callback type 'unknown' received, from=%.*s\n",
242 					dlg->from_uri.len, dlg->from_uri.s);
243 	}
244 }
245 #endif
246 
247 static void
__dialog_sendpublish(struct dlg_cell * dlg,int type,struct dlg_cb_params * _params)248 __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
249 {
250 	str tag = {0,0};
251 	str uri = {0,0};
252 	str target = {0,0};
253 	struct dlginfo_cell *dlginfo = NULL;
254 
255 	struct sip_msg *request = _params->req;
256 	dlginfo = (struct dlginfo_cell*)*_params->param;
257 
258 	if(dlg==NULL || dlginfo==NULL) {
259 		LM_WARN("execution with null parameters - type %d, dlg %p, info %p\n",
260 				type, dlg, dlginfo);
261 		return;
262 	}
263 
264 	/* skip requests that do not control call state */
265 	if(request && (request->REQ_METHOD)&(METHOD_PRACK|METHOD_UPDATE)) {
266 		return;
267 	}
268 	if(include_req_uri) {
269 		uri = dlginfo->req_uri;
270 	} else {
271 		uri = dlginfo->to_uri;
272 	}
273 
274 	switch (type) {
275 		case DLGCB_FAILED:
276 		case DLGCB_TERMINATED:
277 		case DLGCB_EXPIRED:
278 			LM_DBG("dialog over, from=%.*s\n", dlginfo->from_uri.len,
279 					dlginfo->from_uri.s);
280 			if (disable_caller_publish_flag == -1 || !(request
281 						&& (request->flags & (1<<disable_caller_publish_flag))))
282 			{
283 				dialog_publish_multi("terminated", dlginfo->pubruris_caller,
284 						&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
285 						10, 0, 0, &(dlginfo->from_contact),
286 						&target, send_publish_flag==-1?1:0);
287 			}
288 			if (disable_callee_publish_flag == -1 || !(request
289 						&& (request->flags & (1<<disable_callee_publish_flag))))
290 			{
291 				dialog_publish_multi("terminated", dlginfo->pubruris_callee,
292 						&uri, &(dlginfo->from_uri), &(dlginfo->callid), 0,
293 						10, 0, 0, &target, &(dlginfo->from_contact),
294 						send_publish_flag==-1?1:0);
295 			}
296 			break;
297 		case DLGCB_CONFIRMED:
298 		case DLGCB_REQ_WITHIN:
299 		case DLGCB_CONFIRMED_NA:
300 			LM_DBG("dialog confirmed, from=%.*s\n", dlginfo->from_uri.len,
301 					dlginfo->from_uri.s);
302 			if (disable_caller_publish_flag == -1 || !(request
303 						&& (request->flags & (1<<disable_caller_publish_flag))))
304 			{
305 				dialog_publish_multi("confirmed", dlginfo->pubruris_caller,
306 						&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
307 						dlginfo->lifetime, 0, 0, &(dlginfo->from_contact), &target,
308 						send_publish_flag==-1?1:0);
309 			}
310 			if (disable_callee_publish_flag == -1 || !(request
311 						&& (request->flags & (1<<disable_callee_publish_flag))))
312 			{
313 				dialog_publish_multi("confirmed", dlginfo->pubruris_callee, &uri,
314 						&(dlginfo->from_uri), &(dlginfo->callid), 0,
315 						dlginfo->lifetime, 0, 0, &target, &(dlginfo->from_contact),
316 						send_publish_flag==-1?1:0);
317 			}
318 			break;
319 		case DLGCB_EARLY:
320 			LM_DBG("dialog is early, from=%.*s\n", dlginfo->from_uri.len,
321 					dlginfo->from_uri.s);
322 			if (include_tags) {
323 				/* get remotetarget */
324 				if ( !_params->rpl->contact && ((parse_headers(_params->rpl,
325 									HDR_CONTACT_F,0)<0) || !_params->rpl->contact) ) {
326 					LM_ERR("bad reply or missing CONTACT hdr\n");
327 				} else {
328 					if ( parse_contact(_params->rpl->contact)<0 ||
329 							((contact_body_t *)_params->rpl->contact->parsed)->contacts==NULL ||
330 							((contact_body_t *)_params->rpl->contact->parsed)->contacts->next!=NULL ) {
331 						LM_ERR("Malformed CONTACT hdr\n");
332 					} else {
333 						target = ((contact_body_t *)_params->rpl->contact->parsed)->contacts->uri;
334 					}
335 				}
336 				/* get to tag*/
337 				if ( !_params->rpl->to && ((parse_headers(_params->rpl, HDR_TO_F,0)<0)
338 							|| !_params->rpl->to) ) {
339 					LM_ERR("bad reply or missing TO hdr :-/\n");
340 					tag.s = 0;
341 					tag.len = 0;
342 				} else {
343 					tag = get_to(_params->rpl)->tag_value;
344 					if (tag.s==0 || tag.len==0) {
345 						LM_ERR("missing TAG param in TO hdr :-/\n");
346 						tag.s = 0;
347 						tag.len = 0;
348 					}
349 				}
350 				if (disable_caller_publish_flag == -1 || !(request
351 							&& (request->flags & (1<<disable_caller_publish_flag))))
352 				{
353 					if (caller_confirmed) {
354 						dialog_publish_multi("confirmed", dlginfo->pubruris_caller,
355 								&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
356 								dlginfo->lifetime, &(dlginfo->from_tag), &tag,
357 								&(dlginfo->from_contact), &target,
358 								send_publish_flag==-1?1:0);
359 					} else {
360 						dialog_publish_multi("early", dlginfo->pubruris_caller,
361 								&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
362 								dlginfo->lifetime, &(dlginfo->from_tag), &tag,
363 								&(dlginfo->from_contact), &target,
364 								send_publish_flag==-1?1:0);
365 					}
366 				}
367 				if (disable_callee_publish_flag == -1 || !(request &&
368 							(request->flags & (1<<disable_callee_publish_flag))))
369 				{
370 					dialog_publish_multi("early", dlginfo->pubruris_callee, &uri,
371 							&(dlginfo->from_uri), &(dlginfo->callid), 0,
372 							dlginfo->lifetime, &tag, &(dlginfo->from_tag), &target,
373 							&(dlginfo->from_contact), send_publish_flag==-1?1:0);
374 				}
375 
376 			} else {
377 				if (disable_caller_publish_flag == -1 || !(request &&
378 							(request->flags & (1<<disable_caller_publish_flag))))
379 				{
380 					if (caller_confirmed) {
381 						dialog_publish_multi("confirmed", dlginfo->pubruris_caller,
382 								&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
383 								dlginfo->lifetime, 0, 0, &(dlginfo->from_contact),
384 								&target, send_publish_flag==-1?1:0);
385 
386 					} else {
387 						dialog_publish_multi("early", dlginfo->pubruris_caller,
388 								&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
389 								dlginfo->lifetime, 0, 0, &(dlginfo->from_contact),
390 								&target, send_publish_flag==-1?1:0);
391 					}
392 				}
393 				if (disable_callee_publish_flag == -1 || !(request
394 							&& (request->flags & (1<<disable_callee_publish_flag))))
395 				{
396 					dialog_publish_multi("early", dlginfo->pubruris_callee, &uri,
397 							&(dlginfo->from_uri), &(dlginfo->callid), 0,
398 							dlginfo->lifetime, 0, 0, &target,
399 							&(dlginfo->from_contact), send_publish_flag==-1?1:0);
400 				}
401 			}
402 			break;
403 		default:
404 			LM_ERR("unhandled dialog callback type %d received, from=%.*s\n",
405 					type, dlginfo->from_uri.len, dlginfo->from_uri.s);
406 			if (disable_caller_publish_flag == -1 || !(request &&
407 						(request->flags & (1<<disable_caller_publish_flag))))
408 			{
409 				dialog_publish_multi("terminated", dlginfo->pubruris_caller,
410 						&(dlginfo->from_uri), &uri, &(dlginfo->callid), 1,
411 						10, 0, 0, &(dlginfo->from_contact), &target,
412 						send_publish_flag==-1?1:0);
413 			}
414 			if (disable_callee_publish_flag == -1 || !(request &&
415 						(request->flags & (1<<disable_callee_publish_flag))))
416 			{
417 				dialog_publish_multi("terminated", dlginfo->pubruris_callee, &uri,
418 						&(dlginfo->from_uri), &(dlginfo->callid), 0,
419 						10, 0, 0, &target, &(dlginfo->from_contact),
420 						send_publish_flag==-1?1:0);
421 			}
422 	}
423 }
424 
425 /*
426  *  Writes all avps with name avp_name to new str_list (shm mem)
427  *  Be careful: returns NULL pointer if no avp present!
428  *
429  */
get_str_list(unsigned short avp_flags,int_str avp_name)430 struct str_list* get_str_list(unsigned short avp_flags, int_str avp_name) {
431 
432 	int_str avp_value;
433 	unsigned int len;
434 	struct str_list* list_first = 0;
435 	struct str_list* list_current = 0	;
436 	struct search_state st;
437 
438 	if(!search_first_avp(avp_flags, avp_name, &avp_value, &st)) {
439 		return NULL;
440 	}
441 
442 	do {
443 
444 		LM_DBG("AVP found '%.*s'\n", avp_value.s.len, avp_value.s.s);
445 
446 		len = sizeof(struct str_list) + avp_value.s.len;
447 
448 		if(list_current) {
449 			list_current->next = (struct str_list*) shm_malloc( len);
450 			list_current=list_current->next;
451 		} else {
452 			list_current=list_first= (struct str_list*) shm_malloc( len);
453 		}
454 
455 		if (list_current==0) {
456 			SHM_MEM_ERROR;
457 			return 0;
458 		}
459 
460 		memset( list_current, 0, len);
461 
462 		list_current->s.s = (char*)list_current + sizeof(struct str_list);
463 		list_current->s.len = avp_value.s.len;
464 		memcpy(list_current->s.s,avp_value.s.s,avp_value.s.len);
465 
466 
467 
468 	} while(search_next_avp(&st, &avp_value));
469 
470 	return list_first;
471 
472 }
473 
get_dialog_data(struct dlg_cell * dlg,int type)474 struct dlginfo_cell* get_dialog_data(struct dlg_cell *dlg, int type)
475 {
476 	struct dlginfo_cell *dlginfo;
477 	int len;
478 	str* s=NULL;
479 
480 	/* create dlginfo structure to store important data inside the module*/
481 	len = sizeof(struct dlginfo_cell)
482 		+ dlg->from_uri.len
483 		+ dlg->to_uri.len
484 		+ dlg->callid.len
485 		+ dlg->tag[0].len
486 		+ dlg->req_uri.len
487 		+ dlg->contact[0].len;
488 
489 	dlginfo = (struct dlginfo_cell*)shm_malloc( len );
490 	if (dlginfo==0) {
491 		SHM_MEM_ERROR;
492 		return NULL;
493 	}
494 	memset( dlginfo, 0, len);
495 
496 	/* copy from dlg structure to dlginfo structure */
497 	dlginfo->lifetime     = override_lifetime ? override_lifetime : dlg->lifetime;
498 	dlginfo->from_uri.s   = (char*)dlginfo + sizeof(struct dlginfo_cell);
499 	dlginfo->from_uri.len = dlg->from_uri.len;
500 	dlginfo->to_uri.s     = dlginfo->from_uri.s + dlg->from_uri.len;
501 	dlginfo->to_uri.len   = dlg->to_uri.len;
502 	dlginfo->callid.s     = dlginfo->to_uri.s + dlg->to_uri.len;
503 	dlginfo->callid.len   = dlg->callid.len;
504 	dlginfo->from_tag.s   = dlginfo->callid.s + dlg->callid.len;
505 	dlginfo->from_tag.len = dlg->tag[0].len;
506 	dlginfo->req_uri.s    = dlginfo->from_tag.s + dlginfo->from_tag.len;
507 	dlginfo->req_uri.len  = dlg->req_uri.len;
508 	dlginfo->from_contact.s   = dlginfo->req_uri.s + dlginfo->req_uri.len;
509 	dlginfo->from_contact.len = dlg->contact[0].len;
510 
511 	memcpy(dlginfo->from_uri.s, dlg->from_uri.s, dlg->from_uri.len);
512 	memcpy(dlginfo->to_uri.s, dlg->to_uri.s, dlg->to_uri.len);
513 	memcpy(dlginfo->callid.s, dlg->callid.s, dlg->callid.len);
514 	memcpy(dlginfo->from_tag.s, dlg->tag[0].s, dlg->tag[0].len);
515 	memcpy(dlginfo->req_uri.s, dlg->req_uri.s, dlg->req_uri.len);
516 	memcpy(dlginfo->from_contact.s, dlg->contact[0].s, dlg->contact[0].len);
517 
518 	if (use_pubruri_avps) {
519 		if(type==DLGCB_CREATED) {
520 			dlginfo->pubruris_caller = get_str_list(pubruri_caller_avp_type,
521 					pubruri_caller_avp_name);
522 			dlginfo->pubruris_callee = get_str_list(pubruri_callee_avp_type,
523 					pubruri_callee_avp_name);
524 
525 			if(dlginfo->pubruris_callee!=NULL && callee_dlg_var.len>0)
526 				dlg_api.set_dlg_var(dlg, &callee_dlg_var,
527 						&dlginfo->pubruris_callee->s);
528 
529 			if(dlginfo->pubruris_caller!=NULL && caller_dlg_var.len>0)
530 				dlg_api.set_dlg_var(dlg, &caller_dlg_var,
531 						&dlginfo->pubruris_caller->s);
532 
533 		} else {
534 			if(caller_dlg_var.len>0
535 					&& (s = dlg_api.get_dlg_var(dlg, &caller_dlg_var))!=0) {
536 				dlginfo->pubruris_caller =
537 					(struct str_list*)shm_malloc( sizeof(struct str_list) );
538 				if (dlginfo->pubruris_caller==0) {
539 					SHM_MEM_ERROR;
540 					free_dlginfo_cell(dlginfo);
541 					return NULL;
542 				}
543 				memset( dlginfo->pubruris_caller, 0, sizeof(struct str_list));
544 				dlginfo->pubruris_caller->s=*s;
545 				LM_DBG("Found pubruris_caller in dialog '%.*s'\n",
546 						dlginfo->pubruris_caller->s.len, dlginfo->pubruris_caller->s.s);
547 			}
548 
549 			if(callee_dlg_var.len>0
550 					&& (s = dlg_api.get_dlg_var(dlg, &callee_dlg_var))!=0) {
551 				dlginfo->pubruris_callee =
552 					(struct str_list*)shm_malloc( sizeof(struct str_list) );
553 				if (dlginfo->pubruris_callee==0) {
554 					SHM_MEM_ERROR;
555 					free_dlginfo_cell(dlginfo);
556 					return NULL;
557 				}
558 				memset( dlginfo->pubruris_callee, 0, sizeof(struct str_list));
559 				dlginfo->pubruris_callee->s=*s;
560 				LM_DBG("Found pubruris_callee in dialog '%.*s'\n",
561 						dlginfo->pubruris_callee->s.len, dlginfo->pubruris_callee->s.s);
562 			}
563 		}
564 
565 		if(dlginfo->pubruris_caller == 0 && dlginfo->pubruris_callee == 0 ) {
566 			/* No reason to save dlginfo, we have nobody to publish to */
567 			LM_DBG("Neither pubruris_caller nor pubruris_callee found.\n");
568 			free_dlginfo_cell(dlginfo);
569 			return NULL;
570 		}
571 	} else {
572 		dlginfo->pubruris_caller =
573 			(struct str_list*)shm_malloc( sizeof(struct str_list) );
574 		if (dlginfo->pubruris_caller==0) {
575 			SHM_MEM_ERROR;
576 			free_dlginfo_cell(dlginfo);
577 			return NULL;
578 		}
579 		memset( dlginfo->pubruris_caller, 0, sizeof(struct str_list));
580 		dlginfo->pubruris_caller->s=dlginfo->from_uri;
581 
582 		dlginfo->pubruris_callee =
583 			(struct str_list*)shm_malloc( sizeof(struct str_list) );
584 		if (dlginfo->pubruris_callee==0) {
585 			SHM_MEM_ERROR;
586 			free_dlginfo_cell(dlginfo);
587 			return NULL;
588 		}
589 		memset( dlginfo->pubruris_callee, 0, sizeof(struct str_list));
590 
591 		if(include_req_uri) {
592 			dlginfo->pubruris_callee->s = dlginfo->req_uri;
593 		} else {
594 			dlginfo->pubruris_callee->s = dlginfo->to_uri;
595 		}
596 	}
597 
598 	/* register dialog callbacks which triggers sending PUBLISH */
599 	if (dlg_api.register_dlgcb(dlg,
600 				DLGCB_FAILED| DLGCB_CONFIRMED_NA | DLGCB_TERMINATED
601 				| DLGCB_EXPIRED | DLGCB_REQ_WITHIN | DLGCB_EARLY,
602 				__dialog_sendpublish, dlginfo, free_dlginfo_cell) != 0) {
603 		LM_ERR("cannot register callback for interesting dialog types\n");
604 		free_dlginfo_cell(dlginfo);
605 		return NULL;
606 	}
607 
608 #ifdef PUA_DIALOGINFO_DEBUG
609 	/* dialog callback testing (registered last to be executed frist) */
610 	if (dlg_api.register_dlgcb(dlg,
611 				DLGCB_FAILED| DLGCB_CONFIRMED_NA | DLGCB_CONFIRMED
612 				| DLGCB_REQ_WITHIN | DLGCB_TERMINATED | DLGCB_EXPIRED
613 				| DLGCB_EARLY | DLGCB_RESPONSE_FWDED | DLGCB_RESPONSE_WITHIN
614 				| DLGCB_DESTROY,
615 				__dialog_cbtest, NULL, NULL) != 0) {
616 		LM_ERR("cannot register callback for all dialog types\n");
617 		free_dlginfo_cell(dlginfo);
618 		return NULL;
619 	}
620 #endif
621 
622 	return(dlginfo);
623 }
624 
625 	static void
__dialog_created(struct dlg_cell * dlg,int type,struct dlg_cb_params * _params)626 __dialog_created(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
627 {
628 	struct sip_msg *request = _params->req;
629 	struct dlginfo_cell *dlginfo;
630 
631 	if (request==NULL || request->REQ_METHOD != METHOD_INVITE)
632 		return;
633 
634 	if(send_publish_flag > -1 && !(request->flags & (1<<send_publish_flag)))
635 		return;
636 
637 	LM_DBG("new INVITE dialog created: from=%.*s\n",
638 			dlg->from_uri.len, dlg->from_uri.s);
639 
640 	dlginfo=get_dialog_data(dlg, type);
641 	if(dlginfo==NULL)
642 		return;
643 
644 	if (disable_caller_publish_flag == -1 || !(request && (request->flags
645 					& (1<<disable_caller_publish_flag))))
646 	{
647 		dialog_publish_multi("Trying", dlginfo->pubruris_caller,
648 				&(dlg->from_uri),
649 				(include_req_uri)?&(dlg->req_uri):&(dlg->to_uri),
650 				&(dlg->callid), 1, dlginfo->lifetime,
651 				0, 0, 0, 0, (send_publish_flag==-1)?1:0);
652 	}
653 
654 	if (callee_trying && (disable_callee_publish_flag == -1 || !(request
655 					&& (request->flags & (1<<disable_callee_publish_flag)))))
656 	{
657 		dialog_publish_multi("Trying", dlginfo->pubruris_callee,
658 				(include_req_uri)?&(dlg->req_uri):&(dlg->to_uri),
659 				&(dlg->from_uri),
660 				&(dlg->callid), 0, dlginfo->lifetime,
661 				0, 0, 0, 0, (send_publish_flag==-1)?1:0);
662 	}
663 }
664 
665 	static void
__dialog_loaded(struct dlg_cell * dlg,int type,struct dlg_cb_params * _params)666 __dialog_loaded(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
667 {
668 	struct dlginfo_cell *dlginfo;
669 
670 	LM_DBG("INVITE dialog loaded: from=%.*s\n",
671 			dlg->from_uri.len, dlg->from_uri.s);
672 
673 	dlginfo=get_dialog_data(dlg, type);
674 	if(dlginfo!=NULL) {
675 		LM_DBG("dialog info initialized (from=%.*s)\n",
676 				dlg->from_uri.len, dlg->from_uri.s);
677 		/* free_dlginfo_cell(dlginfo); */
678 	}
679 }
680 
681 
682 /**
683  * init module function
684  */
mod_init(void)685 static int mod_init(void)
686 {
687 	bind_pua_t bind_pua;
688 
689 	str s;
690 	pv_spec_t avp_spec;
691 
692 	if(caller_dlg_var.len<=0) {
693 		LM_WARN("pubruri_caller_dlg_var is not set"
694 				" - restore on restart disabled\n");
695 	}
696 
697 	if(callee_dlg_var.len<=0) {
698 		LM_WARN("pubruri_callee_dlg_var is not set"
699 				" - restore on restart disabled\n");
700 	}
701 
702 	bind_pua= (bind_pua_t)find_export("bind_pua", 1,0);
703 	if (!bind_pua)
704 	{
705 		LM_ERR("Can't bind pua\n");
706 		return -1;
707 	}
708 
709 	if (bind_pua(&pua) < 0)
710 	{
711 		LM_ERR("Can't bind pua\n");
712 		return -1;
713 	}
714 	if(pua.send_publish == NULL)
715 	{
716 		LM_ERR("Could not import send_publish\n");
717 		return -1;
718 	}
719 	pua_send_publish= pua.send_publish;
720 
721 	/* bind to the dialog API */
722 	if (load_dlg_api(&dlg_api)!=0) {
723 		LM_ERR("failed to find dialog API - is dialog module loaded?\n");
724 		return -1;
725 	}
726 	/* register dialog creation callback */
727 	if (dlg_api.register_dlgcb(NULL, DLGCB_CREATED, __dialog_created, NULL, NULL) != 0) {
728 		LM_ERR("cannot register callback for dialog creation\n");
729 		return -1;
730 	}
731 	/* register dialog loaded callback */
732 	if (dlg_api.register_dlgcb(NULL, DLGCB_LOADED, __dialog_loaded, NULL, NULL) != 0) {
733 		LM_ERR("cannot register callback for dialog loaded\n");
734 		return -1;
735 	}
736 
737 	if(use_pubruri_avps) {
738 		LM_DBG("configured to use avps for uri values\n");
739 		if((pubruri_caller_avp==NULL || *pubruri_caller_avp==0)
740 				|| (pubruri_callee_avp==NULL || *pubruri_callee_avp==0)) {
741 			LM_ERR("pubruri_caller_avp and pubruri_callee_avp must be set,"
742 					" if use_pubruri_avps is enabled\n");
743 			return -1;
744 		}
745 
746 		s.s = pubruri_caller_avp; s.len = strlen(s.s);
747 		if (pv_parse_spec(&s, &avp_spec)==0	|| avp_spec.type!=PVT_AVP) {
748 			LM_ERR("malformed or non AVP %s AVP definition\n", pubruri_caller_avp);
749 			return -1;
750 		}
751 		if(pv_get_avp_name(0, &avp_spec.pvp, &pubruri_caller_avp_name,
752 					&pubruri_caller_avp_type)!=0) {
753 			LM_ERR("[%s]- invalid AVP definition\n", pubruri_caller_avp);
754 			return -1;
755 		}
756 
757 		s.s = pubruri_callee_avp; s.len = strlen(s.s);
758 		if (pv_parse_spec(&s, &avp_spec)==0	|| avp_spec.type!=PVT_AVP) {
759 			LM_ERR("malformed or non AVP %s AVP definition\n", pubruri_callee_avp);
760 			return -1;
761 		}
762 		if(pv_get_avp_name(0, &avp_spec.pvp, &pubruri_callee_avp_name,
763 					&pubruri_callee_avp_type)!=0) {
764 			LM_ERR("[%s]- invalid AVP definition\n", pubruri_callee_avp);
765 			return -1;
766 		}
767 	} else {
768 		LM_DBG("configured to use headers for uri values\n");
769 	}
770 
771 	return 0;
772 }
773 
free_dlginfo_cell(void * param)774 void free_dlginfo_cell(void *param) {
775 
776 	struct dlginfo_cell *cell = NULL;
777 
778 	if(param==NULL)
779 		return;
780 
781 	cell = param;
782 	free_str_list_all(cell->pubruris_caller);
783 	free_str_list_all(cell->pubruris_callee);
784 
785 	/*if (cell->to_tag) {
786 		shm_free(cell->to_tag);
787 	}*/
788 	shm_free(param);
789 }
790 
791 
free_str_list_all(struct str_list * del_current)792 void free_str_list_all(struct str_list * del_current) {
793 
794 	struct str_list* del_next;
795 
796 	while(del_current) {
797 
798 		del_next = del_current->next;
799 		shm_free(del_current);
800 
801 		del_current=del_next;
802 	}
803 
804 }
805