Merge branch 'master' into treimann/acc-cdr
[sip-router] / modules_k / dialog / dialog.c
1 /*
2  * $Id$
3  *
4  * dialog module - basic support for dialog tracking
5  *
6  * Copyright (C) 2006 Voice Sistem SRL
7  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * History:
26  * --------
27  *  2006-04-14 initial version (bogdan)
28  *  2006-11-28 Added statistic support for the number of early and failed
29  *              dialogs. (Jeffrey Magder - SOMA Networks) 
30  *  2007-04-30 added dialog matching without DID (dialog ID), but based only
31  *              on RFC3261 elements - based on an original patch submitted 
32  *              by Michel Bensoussan <michel@extricom.com> (bogdan)
33  *  2007-05-15 added saving dialogs' information to database (ancuta)
34  *  2007-07-04 added saving dialog cseq, contact, record route 
35  *              and bind_addresses(sock_info) for caller and callee (ancuta)
36  *  2008-04-14 added new type of callback to be triggered when dialogs are 
37  *              loaded from DB (bogdan)
38  *  2010-06-16 added sip-router rpc interface (osas)
39  */
40
41 /**
42  * @defgroup dialog dialog :: Kamailio dialog module
43  * @brief Kamailio dialog module
44  *
45  * The dialog module provides dialog awareness to the Kamailio proxy. Its
46  * functionality is to keep track of the current dialogs, to offer
47  * information about them (like how many dialogs are active) or to manage
48  * them. The module exports several functions that could be used directly
49  * from scripts.
50  * The module, via an internal API, also provide the foundation to build
51  * on top of it more complex dialog-based functionalities via other
52  * Kamailio modules.                       
53  */
54
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <sys/time.h>
59
60 #include "../../sr_module.h"
61 #include "../../lib/srdb1/db.h"
62 #include "../../dprint.h"
63 #include "../../error.h"
64 #include "../../ut.h"
65 #include "../../pvar.h"
66 #include "../../mod_fix.h"
67 #include "../../script_cb.h"
68 #include "../../lib/kcore/faked_msg.h"
69 #include "../../lib/kcore/hash_func.h"
70 #include "../../lib/kcore/kstats_wrapper.h"
71 #include "../../mem/mem.h"
72 #include "../../lib/kmi/mi.h"
73 #include "../../lvalue.h"
74 #include "../../parser/parse_to.h"
75 #include "../../modules/tm/tm_load.h"
76 #include "../../rpc_lookup.h"
77 #include "../rr/api.h"
78 #include "dlg_hash.h"
79 #include "dlg_timer.h"
80 #include "dlg_handlers.h"
81 #include "dlg_load.h"
82 #include "dlg_cb.h"
83 #include "dlg_db_handler.h"
84 #include "dlg_req_within.h"
85 #include "dlg_profile.h"
86 #include "dlg_var.h"
87 #include "dlg_transfer.h"
88
89 MODULE_VERSION
90
91
92 static int mod_init(void);
93 static int child_init(int rank);
94 static void mod_destroy(void);
95
96 /* module parameter */
97 static int dlg_hash_size = 4096;
98 static char* rr_param = "did";
99 static int dlg_flag = -1;
100 static str timeout_spec = {NULL, 0};
101 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
102 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
103 static char* profiles_wv_s = NULL;
104 static char* profiles_nv_s = NULL;
105 str dlg_extra_hdrs = {NULL,0};
106 static int db_fetch_rows = 200;
107 int initial_cbs_inscript = 1;
108
109 str dlg_bridge_controller = {"sip:controller@kamailio.org", 27};
110
111 str ruri_pvar_param = {"$ru", 3};
112 pv_elem_t * ruri_param_model = NULL;
113
114 /* statistic variables */
115 int dlg_enable_stats = 1;
116 int active_dlgs_cnt = 0;
117 int early_dlgs_cnt = 0;
118 int detect_spirals = 1;
119 stat_var *active_dlgs = 0;
120 stat_var *processed_dlgs = 0;
121 stat_var *expired_dlgs = 0;
122 stat_var *failed_dlgs = 0;
123 stat_var *early_dlgs  = 0;
124
125 struct tm_binds d_tmb;
126 struct rr_binds d_rrb;
127 pv_spec_t timeout_avp;
128
129 int dlg_db_mode_param = DB_MODE_NONE;
130
131 /* db stuff */
132 static str db_url = str_init(DEFAULT_DB_URL);
133 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
134
135 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
136                 pv_value_t *res);
137
138 /* commands wrappers and fixups */
139 static int fixup_profile(void** param, int param_no);
140 static int fixup_get_profile2(void** param, int param_no);
141 static int fixup_get_profile3(void** param, int param_no);
142 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
143 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
144 static int w_is_in_profile(struct sip_msg*, char*, char*);
145 static int w_get_profile_size2(struct sip_msg*, char*, char*);
146 static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
147 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
148 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
149 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
150 static int w_dlg_manage(struct sip_msg*, char*, char*);
151 static int w_dlg_bye(struct sip_msg*, char*, char*);
152 static int w_dlg_refer(struct sip_msg*, char*, char*);
153 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
154 static int fixup_dlg_bye(void** param, int param_no);
155 static int fixup_dlg_refer(void** param, int param_no);
156 static int fixup_dlg_bridge(void** param, int param_no);
157 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
158 static int w_is_known_dlg(struct sip_msg *);
159
160 static cmd_export_t cmds[]={
161         {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
162                         0, REQUEST_ROUTE },
163         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
164                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
165         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
166                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
167         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
168                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
169         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
170                         0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
171         {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
172                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
173         {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
174                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
175         {"get_profile_size",(cmd_function)w_get_profile_size2, 2,fixup_get_profile2,
176                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
177         {"get_profile_size",(cmd_function)w_get_profile_size3, 3,fixup_get_profile3,
178                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
179         {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
180                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
181         {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
182                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
183         {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
184                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
185         {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
186                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
187         {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
188                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
189         {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
190                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
191         {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
192                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
193         {"is_known_dlg", (cmd_function)w_is_known_dlg,        0, NULL,
194                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
195         {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
196         {0,0,0,0,0,0}
197 };
198
199 static param_export_t mod_params[]={
200         { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
201         { "hash_size",             INT_PARAM, &dlg_hash_size            },
202         { "rr_param",              STR_PARAM, &rr_param                 },
203         { "dlg_flag",              INT_PARAM, &dlg_flag                 },
204         { "timeout_avp",           STR_PARAM, &timeout_spec.s           },
205         { "default_timeout",       INT_PARAM, &default_timeout          },
206         { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
207         { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
208         { "detect_spirals",        INT_PARAM, &detect_spirals,          },
209         { "db_url",                STR_PARAM, &db_url.s                 },
210         { "db_mode",               INT_PARAM, &dlg_db_mode_param        },
211         { "table_name",            STR_PARAM, &dialog_table_name        },
212         { "call_id_column",        STR_PARAM, &call_id_column.s         },
213         { "from_uri_column",       STR_PARAM, &from_uri_column.s        },
214         { "from_tag_column",       STR_PARAM, &from_tag_column.s        },
215         { "to_uri_column",         STR_PARAM, &to_uri_column.s          },
216         { "to_tag_column",         STR_PARAM, &to_tag_column.s          },
217         { "h_id_column",           STR_PARAM, &h_id_column.s            },
218         { "h_entry_column",        STR_PARAM, &h_entry_column.s         },
219         { "state_column",          STR_PARAM, &state_column.s           },
220         { "start_time_column",     STR_PARAM, &start_time_column.s      },
221         { "timeout_column",        STR_PARAM, &timeout_column.s         },
222         { "to_cseq_column",        STR_PARAM, &to_cseq_column.s         },
223         { "from_cseq_column",      STR_PARAM, &from_cseq_column.s       },
224         { "to_route_column",       STR_PARAM, &to_route_column.s        },
225         { "from_route_column",     STR_PARAM, &from_route_column.s      },
226         { "to_contact_column",     STR_PARAM, &to_contact_column.s      },
227         { "from_contact_column",   STR_PARAM, &from_contact_column.s    },
228         { "to_sock_column",        STR_PARAM, &to_sock_column.s         },
229         { "from_sock_column",      STR_PARAM, &from_sock_column.s       },
230         { "sflags_column",         STR_PARAM, &sflags_column.s          },
231         { "toroute_name_column",   STR_PARAM, &toroute_name_column.s    },
232
233         { "vars_table_name",       STR_PARAM, &dialog_vars_table_name   },
234         { "vars_h_id_column",      STR_PARAM, &vars_h_id_column.s       },
235         { "vars_h_entry_column",   STR_PARAM, &vars_h_entry_column.s    },
236         { "vars_key_column",       STR_PARAM, &vars_key_column.s        },
237         { "vars_value_column",     STR_PARAM, &vars_value_column.s      },
238
239         { "db_update_period",      INT_PARAM, &db_update_period         },
240         { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
241         { "profiles_with_value",   STR_PARAM, &profiles_wv_s            },
242         { "profiles_no_value",     STR_PARAM, &profiles_nv_s            },
243         { "bridge_controller",     STR_PARAM, &dlg_bridge_controller.s  },
244         { "ruri_pvar",             STR_PARAM, &ruri_pvar_param.s        },
245         { "initial_cbs_inscript",  INT_PARAM, &initial_cbs_inscript     },
246         { 0,0,0 }
247 };
248
249
250 static stat_export_t mod_stats[] = {
251         {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
252         {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
253         {"processed_dialogs" ,  0,              &processed_dlgs    },
254         {"expired_dialogs" ,    0,              &expired_dlgs      },
255         {"failed_dialogs",      0,              &failed_dlgs       },
256         {0,0,0}
257 };
258
259 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param);
260
261 static mi_export_t mi_cmds[] = {
262         { "dlg_list",           mi_print_dlgs,       0,  0,  0},
263         { "dlg_list_ctx",       mi_print_dlgs_ctx,   0,  0,  0},
264         { "dlg_end_dlg",        mi_terminate_dlg,    0,  0,  0},
265         { "dlg_terminate_dlg",  mi_terminate_dlgs,   0,  0,  0},
266         { "profile_get_size",   mi_get_profile,      0,  0,  0},
267         { "profile_list_dlgs",  mi_profile_list,     0,  0,  0},
268         { "dlg_bridge",         mi_dlg_bridge,       0,  0,  0},
269         { 0, 0, 0, 0, 0}
270 };
271
272 static rpc_export_t rpc_methods[];
273
274 static pv_export_t mod_items[] = {
275         { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
276                 0, 0, 0, 0 },
277         { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
278                 0, 0, 0, 0 },
279         { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
280                 0, 0, 0, 0 },
281         { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
282                 pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
283         { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
284                 0, pv_parse_dlg_name, 0, 0, 0 },
285         { {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
286                 pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
287         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
288 };
289
290 struct module_exports exports= {
291         "dialog",        /* module's name */
292         DEFAULT_DLFLAGS, /* dlopen flags */
293         cmds,            /* exported functions */
294         mod_params,      /* param exports */
295         mod_stats,       /* exported statistics */
296         mi_cmds,         /* exported MI functions */
297         mod_items,       /* exported pseudo-variables */
298         0,               /* extra processes */
299         mod_init,        /* module initialization function */
300         0,               /* reply processing function */
301         mod_destroy,
302         child_init       /* per-child init function */
303 };
304
305
306 static int fixup_profile(void** param, int param_no)
307 {
308         struct dlg_profile_table *profile;
309         pv_elem_t *model=NULL;
310         str s;
311
312         s.s = (char*)(*param);
313         s.len = strlen(s.s);
314         if(s.len==0) {
315                 LM_ERR("param %d is empty string!\n", param_no);
316                 return E_CFG;
317         }
318
319         if (param_no==1) {
320                 profile = search_dlg_profile( &s );
321                 if (profile==NULL) {
322                         LM_CRIT("profile <%s> not definited\n",s.s);
323                         return E_CFG;
324                 }
325                 pkg_free(*param);
326                 *param = (void*)profile;
327                 return 0;
328         } else if (param_no==2) {
329                 if(pv_parse_format(&s ,&model) || model==NULL) {
330                         LM_ERR("wrong format [%s] for value param!\n", s.s);
331                         return E_CFG;
332                 }
333                 *param = (void*)model;
334         }
335         return 0;
336 }
337
338
339 static int fixup_get_profile2(void** param, int param_no)
340 {
341         pv_spec_t *sp;
342         int ret;
343
344         if (param_no==1) {
345                 return fixup_profile(param, 1);
346         } else if (param_no==2) {
347                 ret = fixup_pvar_null(param, 1);
348                 if (ret<0) return ret;
349                 sp = (pv_spec_t*)(*param);
350                 if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
351                         LM_ERR("return must be an AVP or SCRIPT VAR!\n");
352                         return E_SCRIPT;
353                 }
354         }
355         return 0;
356 }
357
358
359 static int fixup_get_profile3(void** param, int param_no)
360 {
361         if (param_no==1) {
362                 return fixup_profile(param, 1);
363         } else if (param_no==2) {
364                 return fixup_profile(param, 2);
365         } else if (param_no==3) {
366                 return fixup_get_profile2( param, 2);
367         }
368         return 0;
369 }
370
371
372
373 int load_dlg( struct dlg_binds *dlgb )
374 {
375         dlgb->register_dlgcb = register_dlgcb;
376         dlgb->terminate_dlg = dlg_bye_all;
377         dlgb->set_dlg_var = set_dlg_variable;
378         dlgb->get_dlg_var = get_dlg_variable;
379         return 1;
380 }
381
382
383 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
384                 pv_value_t *res)
385 {
386         int n;
387         int l;
388         char *ch;
389
390         if(msg==NULL || res==NULL)
391                 return -1;
392
393         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
394         l = 0;
395         ch = int2str( n, &l);
396
397         res->rs.s = ch;
398         res->rs.len = l;
399
400         res->ri = n;
401         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
402
403         return 0;
404 }
405
406
407 static int mod_init(void)
408 {
409         unsigned int n;
410
411
412 #ifdef STATISTICS
413         /* register statistics */
414         if (register_module_stats( exports.name, mod_stats)!=0 ) {
415                 LM_ERR("failed to register core statistics\n");
416                 return -1;
417         }
418 #endif
419
420         if(register_mi_mod(exports.name, mi_cmds)!=0)
421         {
422                 LM_ERR("failed to register MI commands\n");
423                 return -1;
424         }
425
426         if (rpc_register_array(rpc_methods)!=0) {
427                 LM_ERR("failed to register RPC commands\n");
428                 return -1;
429         }
430
431         if(faked_msg_init()<0)
432                 return -1;
433
434         if (timeout_spec.s)
435                 timeout_spec.len = strlen(timeout_spec.s);
436
437         dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
438         db_url.len = strlen(db_url.s);
439         call_id_column.len = strlen(call_id_column.s);
440         from_uri_column.len = strlen(from_uri_column.s);
441         from_tag_column.len = strlen(from_tag_column.s);
442         to_uri_column.len = strlen(to_uri_column.s);
443         to_tag_column.len = strlen(to_tag_column.s);
444         h_id_column.len = strlen(h_id_column.s);
445         h_entry_column.len = strlen(h_entry_column.s);
446         state_column.len = strlen(state_column.s);
447         start_time_column.len = strlen(start_time_column.s);
448         timeout_column.len = strlen(timeout_column.s);
449         to_cseq_column.len = strlen(to_cseq_column.s);
450         from_cseq_column.len = strlen(from_cseq_column.s);
451         to_route_column.len = strlen(to_route_column.s);
452         from_route_column.len = strlen(from_route_column.s);
453         to_contact_column.len = strlen(to_contact_column.s);
454         from_contact_column.len = strlen(from_contact_column.s);
455         to_sock_column.len = strlen(to_sock_column.s);
456         from_sock_column.len = strlen(from_sock_column.s);
457         sflags_column.len = strlen(sflags_column.s);
458         toroute_name_column.len = strlen(toroute_name_column.s);
459         dialog_table_name.len = strlen(dialog_table_name.s);
460
461         dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
462         vars_h_id_column.len = strlen(vars_h_id_column.s);
463         vars_h_entry_column.len = strlen(vars_h_entry_column.s);
464         vars_key_column.len = strlen(vars_key_column.s);
465         vars_value_column.len = strlen(vars_value_column.s);
466
467         /* param checkings */
468         if (dlg_flag==-1) {
469                 LM_ERR("no dlg flag set!!\n");
470                 return -1;
471         } else if (dlg_flag>MAX_FLAG) {
472                 LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
473                 return -1;
474         }
475
476         if (rr_param==0 || rr_param[0]==0) {
477                 LM_ERR("empty rr_param!!\n");
478                 return -1;
479         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
480                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
481                 return -1;
482         }
483
484         if (timeout_spec.s) {
485                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
486                                 && (timeout_avp.type!=PVT_AVP)){
487                         LM_ERR("malformed or non AVP timeout "
488                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
489                         return -1;
490                 }
491         }
492
493         if (default_timeout<=0) {
494                 LM_ERR("0 default_timeout not accepted!!\n");
495                 return -1;
496         }
497
498         if (ruri_pvar_param.s==NULL || *ruri_pvar_param.s=='\0') {
499                 LM_ERR("invalid r-uri PV string\n");
500                 return -1;
501         }
502         ruri_pvar_param.len = strlen(ruri_pvar_param.s);
503         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
504                                 || ruri_param_model==NULL) {
505                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
506                 return -1;
507         }
508
509         if (initial_cbs_inscript != 0 && initial_cbs_inscript != 1) {
510                 LM_ERR("invalid parameter for running initial callbacks in-script (must be either 0 or 1)\n");
511                 return -1;
512         }
513
514         /* update the len of the extra headers */
515         if (dlg_extra_hdrs.s)
516                 dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
517
518         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
519         seq_match_mode!=SEQ_MATCH_FALLBACK &&
520         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
521                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
522                 return -1;
523         }
524
525         if (detect_spirals != 0 && detect_spirals != 1) {
526                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
527                 return -1;
528         }
529
530         /* if statistics are disabled, prevent their registration to core */
531         if (dlg_enable_stats==0)
532                 exports.stats = 0;
533
534         /* create profile hashes */
535         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
536                 LM_ERR("failed to add profiles without value\n");
537                 return -1;
538         }
539         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
540                 LM_ERR("failed to add profiles with value\n");
541                 return -1;
542         }
543
544         /* load the TM API */
545         if (load_tm_api(&d_tmb)!=0) {
546                 LM_ERR("can't load TM API\n");
547                 return -1;
548         }
549
550         /* load RR API also */
551         if (load_rr_api(&d_rrb)!=0) {
552                 LM_ERR("can't load RR API\n");
553                 return -1;
554         }
555
556         /* register callbacks*/
557         /* listen for all incoming requests  */
558         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
559                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
560                 return -1;
561         }
562
563         /* listen for all routed requests  */
564         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
565                 LM_ERR("cannot register RR callback\n");
566                 return -1;
567         }
568
569         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
570                 LM_ERR("cannot regsiter script callback");
571                 return -1;
572         }
573         if (register_script_cb(dlg_cfg_cb,
574                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
575         {
576                 LM_ERR("cannot regsiter pre-script ctx callback\n");
577                 return -1;
578         }
579         if (register_script_cb(dlg_cfg_cb,
580                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
581         {
582                 LM_ERR("cannot regsiter post-script ctx callback\n");
583                 return -1;
584         }
585
586         if (register_script_cb( spiral_detect_reset, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
587                 LM_ERR("cannot register req pre-script spiral detection reset callback\n");
588                 return -1;
589         }
590
591         if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
592                 LM_ERR("failed to register timer \n");
593                 return -1;
594         }
595
596         /* init handlers */
597         init_dlg_handlers( rr_param, dlg_flag,
598                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
599
600         /* init timer */
601         if (init_dlg_timer(dlg_ontimeout)!=0) {
602                 LM_ERR("cannot init timer list\n");
603                 return -1;
604         }
605
606         /* initialized the hash table */
607         for( n=0 ; n<(8*sizeof(n)) ; n++) {
608                 if (dlg_hash_size==(1<<n))
609                         break;
610                 if (dlg_hash_size<(1<<n)) {
611                         LM_WARN("hash_size is not a power "
612                                 "of 2 as it should be -> rounding from %d to %d\n",
613                                 dlg_hash_size, 1<<(n-1));
614                         dlg_hash_size = 1<<(n-1);
615                 }
616         }
617
618         if ( init_dlg_table(dlg_hash_size)<0 ) {
619                 LM_ERR("failed to create hash table\n");
620                 return -1;
621         }
622
623         /* if a database should be used to store the dialogs' information */
624         dlg_db_mode = dlg_db_mode_param;
625         if (dlg_db_mode==DB_MODE_NONE) {
626                 db_url.s = 0; db_url.len = 0;
627         } else {
628                 if (dlg_db_mode!=DB_MODE_REALTIME &&
629                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
630                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
631                         return -1;
632                 }
633                 if ( !db_url.s || db_url.len==0 ) {
634                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
635                         return -1;
636                 }
637                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
638                         LM_ERR("failed to initialize the DB support\n");
639                         return -1;
640                 }
641                 run_load_callbacks();
642         }
643
644         destroy_dlg_callbacks( DLGCB_LOADED );
645
646         return 0;
647 }
648
649
650 static int child_init(int rank)
651 {
652         dlg_db_mode = dlg_db_mode_param;
653
654         if (rank==1) {
655                 if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
656                 if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
657         }
658
659         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
660         (rank>0 || rank==PROC_TIMER)) ||
661         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
662                 if ( dlg_connect_db(&db_url) ) {
663                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
664                         return -1;
665                 }
666         }
667
668         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
669          * for the rest of the processes will be the same as DB_MODE_NONE */
670         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
671                 dlg_db_mode = DB_MODE_NONE;
672         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
673         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
674                         rank==PROC_MAIN)
675                 dlg_db_mode = DB_MODE_NONE;
676
677         return 0;
678 }
679
680
681 static void mod_destroy(void)
682 {
683         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
684                 dialog_update_db(0, 0);
685                 destroy_dlg_db();
686         }
687         /* no DB interaction from now on */
688         dlg_db_mode = DB_MODE_NONE;
689         destroy_dlg_table();
690         destroy_dlg_timer();
691         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
692         destroy_dlg_handlers();
693         destroy_dlg_profiles();
694 }
695
696
697
698 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
699 {
700         pv_elem_t *pve;
701         str val_s;
702
703         pve = (pv_elem_t *)value;
704
705         if (((struct dlg_profile_table*)profile)->has_value) {
706                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
707                 val_s.len == 0 || val_s.s == NULL) {
708                         LM_WARN("cannot get string for value\n");
709                         return -1;
710                 }
711                 if ( set_dlg_profile( msg, &val_s,
712                 (struct dlg_profile_table*)profile) < 0 ) {
713                         LM_ERR("failed to set profile");
714                         return -1;
715                 }
716         } else {
717                 if ( set_dlg_profile( msg, NULL,
718                 (struct dlg_profile_table*)profile) < 0 ) {
719                         LM_ERR("failed to set profile");
720                         return -1;
721                 }
722         }
723         return 1;
724 }
725
726
727
728 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
729 {
730         pv_elem_t *pve;
731         str val_s;
732
733         pve = (pv_elem_t *)value;
734
735         if (((struct dlg_profile_table*)profile)->has_value) {
736                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
737                 val_s.len == 0 || val_s.s == NULL) {
738                         LM_WARN("cannot get string for value\n");
739                         return -1;
740                 }
741                 if ( unset_dlg_profile( msg, &val_s,
742                 (struct dlg_profile_table*)profile) < 0 ) {
743                         LM_ERR("failed to unset profile");
744                         return -1;
745                 }
746         } else {
747                 if ( unset_dlg_profile( msg, NULL,
748                 (struct dlg_profile_table*)profile) < 0 ) {
749                         LM_ERR("failed to unset profile");
750                         return -1;
751                 }
752         }
753         return 1;
754 }
755
756
757
758 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
759 {
760         pv_elem_t *pve;
761         str val_s;
762
763         pve = (pv_elem_t *)value;
764
765         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
766                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
767                 val_s.len == 0 || val_s.s == NULL) {
768                         LM_WARN("cannot get string for value\n");
769                         return -1;
770                 }
771                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
772                         &val_s);
773         } else {
774                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
775                         NULL);
776         }
777 }
778
779
780 /**
781  * get dynamic name profile size
782  */
783 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
784                 char *value, char *result)
785 {
786         pv_elem_t *pve;
787         str val_s;
788         pv_spec_t *sp_dest;
789         unsigned int size;
790         pv_value_t val;
791
792         if(result!=NULL)
793         {
794                 pve = (pv_elem_t *)value;
795                 sp_dest = (pv_spec_t *)result;
796         } else {
797                 pve = NULL;
798                 sp_dest = (pv_spec_t *)value;
799         }
800         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
801                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
802                 val_s.len == 0 || val_s.s == NULL) {
803                         LM_WARN("cannot get string for value\n");
804                         return -1;
805                 }
806                 size = get_profile_size( (struct dlg_profile_table*)profile, &val_s );
807         } else {
808                 size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
809         }
810
811         memset(&val, 0, sizeof(pv_value_t));
812         val.flags = PV_VAL_INT|PV_TYPE_INT;
813         val.ri = (int)size;
814
815         if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
816         {
817                 LM_ERR("setting profile PV failed\n");
818                 return -1;
819         }
820
821         return 1;
822 }
823
824
825 /**
826  * get static name profile size
827  */
828 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
829 {
830         return w_get_profile_size3(msg, profile, result, NULL);
831 }
832
833
834 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
835 {
836         dlg_ctx_t *dctx;
837         int val;
838
839         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
840         {
841                 LM_ERR("no flag value\n");
842                 return -1;
843         }
844         if(val<0 || val>31)
845                 return -1;
846         if ( (dctx=dlg_get_dlg_ctx())==NULL )
847                 return -1;
848
849         dctx->flags |= 1<<val;
850         if(dctx->dlg)
851                 dctx->dlg->sflags |= 1<<val;
852         return 1;
853 }
854
855
856 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
857 {
858         dlg_ctx_t *dctx;
859         int val;
860
861         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
862         {
863                 LM_ERR("no flag value\n");
864                 return -1;
865         }
866         if(val<0 || val>31)
867                 return -1;
868
869         if ( (dctx=dlg_get_dlg_ctx())==NULL )
870                 return -1;
871
872         dctx->flags &= ~(1<<val);
873         if(dctx->dlg)
874                 dctx->dlg->sflags &= ~(1<<val);
875         return 1;
876 }
877
878
879 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
880 {
881         dlg_ctx_t *dctx;
882         int val;
883
884         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
885         {
886                 LM_ERR("no flag value\n");
887                 return -1;
888         }
889         if(val<0 || val>31)
890                 return -1;
891
892         if ( (dctx=dlg_get_dlg_ctx())==NULL )
893                 return -1;
894
895         if(dctx->dlg)
896                 return (dctx->dlg->sflags&(1<<val))?1:-1;
897         return (dctx->flags&(1<<val))?1:-1;
898 }
899
900 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
901 {
902         str tag;
903         int backup_mode;
904
905         if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
906         {
907                 LM_ERR("bad TO header\n");
908                 return -1;
909         }
910         tag = get_to(msg)->tag_value;
911         if(tag.s!=0 && tag.len!=0)
912         {
913                 backup_mode = seq_match_mode;
914                 seq_match_mode = SEQ_MATCH_NO_ID;
915                 dlg_onroute(msg, NULL, NULL);
916                 seq_match_mode = backup_mode;
917         } else {
918                 if(dlg_new_dialog(msg, 0, initial_cbs_inscript)!=0)
919                         return -1;
920         }
921         return 1;
922 }
923
924 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
925 {
926         struct dlg_cell *dlg;
927         int n;
928
929         dlg = dlg_get_ctx_dialog();
930         if(dlg==NULL)
931                 return -1;
932         
933         n = (int)(long)side;
934         if(n==1)
935         {
936                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
937                         return -1;
938                 return 1;
939         } else if(n==2) {
940                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
941                         return -1;
942                 return 1;
943         } else {
944                 if(dlg_bye_all(dlg, NULL)!=0)
945                         return -1;
946                 return 1;
947         }
948 }
949
950 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
951 {
952         struct dlg_cell *dlg;
953         int n;
954         str st = {0,0};
955
956         dlg = dlg_get_ctx_dialog();
957         if(dlg==NULL)
958                 return -1;
959         
960         n = (int)(long)side;
961
962         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
963         {
964                 LM_ERR("unable to get To\n");
965                 return -1;
966         }
967         if(st.s==NULL || st.len == 0)
968         {
969                 LM_ERR("invalid To parameter\n");
970                 return -1;
971         }
972         if(n==1)
973         {
974                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
975                         return -1;
976         } else {
977                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
978                         return -1;
979         }
980         return 1;
981 }
982
983 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
984 {
985         str sf = {0,0};
986         str st = {0,0};
987         str so = {0,0};
988
989         if(from==0 || to==0 || op==0)
990         {
991                 LM_ERR("invalid parameters\n");
992                 return -1;
993         }
994
995         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
996         {
997                 LM_ERR("unable to get From\n");
998                 return -1;
999         }
1000         if(sf.s==NULL || sf.len == 0)
1001         {
1002                 LM_ERR("invalid From parameter\n");
1003                 return -1;
1004         }
1005         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1006         {
1007                 LM_ERR("unable to get To\n");
1008                 return -1;
1009         }
1010         if(st.s==NULL || st.len == 0)
1011         {
1012                 LM_ERR("invalid To parameter\n");
1013                 return -1;
1014         }
1015         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
1016         {
1017                 LM_ERR("unable to get OP\n");
1018                 return -1;
1019         }
1020
1021         if(dlg_bridge(&sf, &st, &so)!=0)
1022                 return -1;
1023         return 1;
1024 }
1025
1026
1027 static int fixup_dlg_bye(void** param, int param_no)
1028 {
1029         char *val;
1030         int n = 0;
1031
1032         if (param_no==1) {
1033                 val = (char*)*param;
1034                 if (strcasecmp(val,"all")==0) {
1035                         n = 0;
1036                 } else if (strcasecmp(val,"caller")==0) {
1037                         n = 1;
1038                 } else if (strcasecmp(val,"callee")==0) {
1039                         n = 2;
1040                 } else {
1041                         LM_ERR("invalid param \"%s\"\n", val);
1042                         return E_CFG;
1043                 }
1044                 pkg_free(*param);
1045                 *param=(void*)(long)n;
1046         } else {
1047                 LM_ERR("called with parameter != 1\n");
1048                 return E_BUG;
1049         }
1050         return 0;
1051 }
1052
1053 static int fixup_dlg_refer(void** param, int param_no)
1054 {
1055         char *val;
1056         int n = 0;
1057
1058         if (param_no==1) {
1059                 val = (char*)*param;
1060                 if (strcasecmp(val,"caller")==0) {
1061                         n = 1;
1062                 } else if (strcasecmp(val,"callee")==0) {
1063                         n = 2;
1064                 } else {
1065                         LM_ERR("invalid param \"%s\"\n", val);
1066                         return E_CFG;
1067                 }
1068                 pkg_free(*param);
1069                 *param=(void*)(long)n;
1070         } else if (param_no==2) {
1071                 return fixup_spve_null(param, 1);
1072         } else {
1073                 LM_ERR("called with parameter idx %d\n", param_no);
1074                 return E_BUG;
1075         }
1076         return 0;
1077 }
1078
1079 static int fixup_dlg_bridge(void** param, int param_no)
1080 {
1081         if (param_no>=1 && param_no<=3) {
1082                 return fixup_spve_null(param, 1);
1083         } else {
1084                 LM_ERR("called with parameter idx %d\n", param_no);
1085                 return E_BUG;
1086         }
1087         return 0;
1088 }
1089
1090 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1091 {
1092         struct dlg_cell *dlg = NULL;
1093         str sc = {0,0};
1094         str sf = {0,0};
1095         str st = {0,0};
1096         unsigned int dir = 0;
1097
1098         if(ci==0 || ft==0 || tt==0)
1099         {
1100                 LM_ERR("invalid parameters\n");
1101                 return -1;
1102         }
1103
1104         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1105         {
1106                 LM_ERR("unable to get Call-ID\n");
1107                 return -1;
1108         }
1109         if(sc.s==NULL || sc.len == 0)
1110         {
1111                 LM_ERR("invalid Call-ID parameter\n");
1112                 return -1;
1113         }
1114         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1115         {
1116                 LM_ERR("unable to get From tag\n");
1117                 return -1;
1118         }
1119         if(sf.s==NULL || sf.len == 0)
1120         {
1121                 LM_ERR("invalid From tag parameter\n");
1122                 return -1;
1123         }
1124         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1125         {
1126                 LM_ERR("unable to get To Tag\n");
1127                 return -1;
1128         }
1129         if(st.s==NULL || st.len == 0)
1130         {
1131                 LM_ERR("invalid To tag parameter\n");
1132                 return -1;
1133         }
1134
1135         dlg = get_dlg(&sc, &sf, &st, &dir, NULL);
1136         if(dlg==NULL)
1137                 return -1;
1138         current_dlg_pointer = dlg;
1139         _dlg_ctx.dlg = dlg;
1140         _dlg_ctx.dir = dir;
1141         return 1;
1142 }
1143
1144 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
1145 {
1146         str from = {0,0};
1147         str to = {0,0};
1148         str op = {0,0};
1149         struct mi_node* node;
1150
1151         node = cmd_tree->node.kids;
1152         if(node == NULL)
1153                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1154         from = node->value;
1155         if(from.len<=0 || from.s==NULL)
1156         {
1157                 LM_ERR("bad From value\n");
1158                 return init_mi_tree( 500, "Bad From value", 14);
1159         }
1160
1161         node = node->next;
1162         if(node == NULL)
1163                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1164         to = node->value;
1165         if(to.len<=0 || to.s == NULL)
1166         {
1167                 return init_mi_tree(500, "Bad To value", 12);
1168         }
1169
1170         node= node->next;
1171         if(node != NULL)
1172         {
1173                 op = node->value;
1174                 if(op.len<=0 || op.s==NULL)
1175                 {
1176                         return init_mi_tree(500, "Bad OP value", 12);
1177                 }
1178         }
1179
1180         if(dlg_bridge(&from, &to, &op)!=0)
1181                 return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
1182
1183         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
1184 }
1185
1186 /**************************** RPC functions ******************************/
1187 /*!
1188  * \brief Helper method that outputs a dialog via the RPC interface
1189  * \see rpc_print_dlg
1190  * \param rpc RPC node that should be filled
1191  * \param c RPC void pointer
1192  * \param dlg printed dialog
1193  * \param with_context if 1 then the dialog context will be also printed
1194  * \return 0 on success, -1 on failure
1195  */
1196 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *dlg, int with_context)
1197 {
1198         rpc_cb_ctx_t rpc_cb;
1199
1200         rpc->printf(c, "hash:%u:%u state:%u timestart:%u timeout:%u",
1201                 dlg->h_entry, dlg->h_id, dlg->state, dlg->start_ts, dlg->tl.timeout);
1202         rpc->printf(c, "\tcallid:%.*s from_tag:%.*s to_tag:%.*s",
1203                 dlg->callid.len, dlg->callid.s,
1204                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
1205                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1206         rpc->printf(c, "\tfrom_uri:%.*s to_uri:%.*s",
1207                 dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s);
1208         rpc->printf(c, "\tcaller_contact:%.*s caller_cseq:%.*s",
1209                 dlg->contact[DLG_CALLER_LEG].len, dlg->contact[DLG_CALLER_LEG].s,
1210                 dlg->cseq[DLG_CALLER_LEG].len, dlg->cseq[DLG_CALLER_LEG].s);
1211         rpc->printf(c, "\tcaller_route_set: %.*s",
1212                 dlg->route_set[DLG_CALLER_LEG].len, dlg->route_set[DLG_CALLER_LEG].s);
1213         rpc->printf(c, "\tcallee_contact:%.*s callee_cseq:%.*s",
1214                 dlg->contact[DLG_CALLEE_LEG].len, dlg->contact[DLG_CALLEE_LEG].s,
1215                 dlg->cseq[DLG_CALLEE_LEG].len, dlg->cseq[DLG_CALLEE_LEG].s);
1216         rpc->printf(c, "\tcallee_route_set: %.*s",
1217                 dlg->route_set[DLG_CALLEE_LEG].len, dlg->route_set[DLG_CALLEE_LEG].s);
1218         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
1219                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:%.*s",
1220                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
1221                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
1222         } else {
1223                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:",
1224                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s);
1225         }
1226         if (with_context) {
1227                 rpc_cb.rpc = rpc;
1228                 rpc_cb.c = c;
1229                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1230         }
1231 }
1232
1233 /*!
1234  * \brief Helper function that outputs all dialogs via the RPC interface
1235  * \see rpc_print_dlgs
1236  * \param rpc RPC node that should be filled
1237  * \param c RPC void pointer
1238  * \param with_context if 1 then the dialog context will be also printed
1239  */
1240 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
1241 {
1242         struct dlg_cell *dlg;
1243         unsigned int i;
1244
1245         for( i=0 ; i<d_table->size ; i++ ) {
1246                 dlg_lock( d_table, &(d_table->entries[i]) );
1247
1248                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
1249                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1250                 }
1251                 dlg_unlock( d_table, &(d_table->entries[i]) );
1252         }
1253 }
1254
1255 /*!
1256  * \brief Helper function that outputs a dialog via the RPC interface
1257  * \see rpc_print_dlgs
1258  * \param rpc RPC node that should be filled
1259  * \param c RPC void pointer
1260  * \param with_context if 1 then the dialog context will be also printed
1261  */
1262 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
1263         str callid, from_tag;
1264         struct dlg_entry *d_entry;
1265         struct dlg_cell *dlg;
1266         unsigned int h_entry;
1267
1268         if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;
1269
1270         h_entry = core_hash( &callid, 0, d_table->size);
1271         d_entry = &(d_table->entries[h_entry]);
1272         dlg_lock( d_table, d_entry);
1273         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
1274                 if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
1275                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1276                 }
1277         }
1278         dlg_unlock( d_table, d_entry);
1279 }
1280
1281 /*!
1282  * \brief Helper function that outputs the size of a given profile via the RPC interface
1283  * \see rpc_profile_get_size
1284  * \see rpc_profile_w_value_get_size
1285  * \param rpc RPC node that should be filled
1286  * \param c RPC void pointer
1287  * \param profile_name the given profile
1288  * \param value the given profile value
1289  */
1290 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name, str *value) {
1291         unsigned int size;
1292         struct dlg_profile_table *profile;
1293
1294         profile = search_dlg_profile( profile_name );
1295         if (!profile) {
1296                 rpc->printf(c, "Non existing profile:%.*s",
1297                         profile_name->len, profile_name->s);
1298                 return;
1299         }
1300         size = get_profile_size(profile, value);
1301         if (value) {
1302                 rpc->printf(c, "Profile:%.*s => profile:%.*s value:%.*s count:%u",
1303                         profile_name->len, profile_name->s,
1304                         profile->name.len, profile->name.s,
1305                         value->len, value->s, size);
1306                 return;
1307         } else {
1308                 rpc->printf(c, "Profile:%.*s => profile:%.*s value: count:%u",
1309                         profile_name->len, profile_name->s,
1310                         profile->name.len, profile->name.s, size);
1311                 return;
1312         }
1313         return;
1314 }
1315
1316 /*!
1317  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
1318  * \see rpc_profile_print_dlgs
1319  * \see rpc_profile_w_value_print_dlgs
1320  * \param rpc RPC node that should be filled
1321  * \param c RPC void pointer
1322  * \param profile_name the given profile
1323  * \param value the given profile value
1324  * \param with_context if 1 then the dialog context will be also printed
1325  */
1326 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name, str *value) {
1327         struct dlg_profile_table *profile;
1328         struct dlg_profile_hash *ph;
1329         unsigned int i;
1330
1331         profile = search_dlg_profile( profile_name );
1332         if (!profile) {
1333                 rpc->printf(c, "Non existing profile:%.*s",
1334                         profile_name->len, profile_name->s);
1335                 return;
1336         }
1337
1338         /* go through the hash and print the dialogs */
1339         if (profile->has_value==0 || value==NULL) {
1340                 /* no value */
1341                 lock_get( &profile->lock );
1342                 for ( i=0 ; i< profile->size ; i++ ) {
1343                         ph = profile->entries[i].first;
1344                         if(ph) {
1345                                 do {
1346                                         /* print dialog */
1347                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1348                                         /* next */
1349                                         ph=ph->next;
1350                                 }while(ph!=profile->entries[i].first);
1351                         }
1352                         lock_release(&profile->lock);
1353                 }
1354         } else {
1355                 /* check for value also */
1356                 lock_get( &profile->lock );
1357                 for ( i=0 ; i< profile->size ; i++ ) {
1358                         ph = profile->entries[i].first;
1359                         if(ph) {
1360                                 do {
1361                                         if ( value->len==ph->value.len &&
1362                                                 memcmp(value->s,ph->value.s,value->len)==0 ) {
1363                                                 /* print dialog */
1364                                                 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1365                                         }
1366                                         /* next */
1367                                         ph=ph->next;
1368                                 }while(ph!=profile->entries[i].first);
1369                         }
1370                         lock_release(&profile->lock);
1371                 }
1372         }
1373 }
1374
1375 /*
1376  * Wrapper around is_known_dlg().
1377  */
1378
1379 static int w_is_known_dlg(struct sip_msg *msg) {
1380         return  is_known_dlg(msg);
1381 }
1382
1383 static const char *rpc_print_dlgs_doc[2] = {
1384         "Print all dialogs", 0
1385 };
1386 static const char *rpc_print_dlgs_ctx_doc[2] = {
1387         "Print all dialogs with associated context", 0
1388 };
1389 static const char *rpc_print_dlg_doc[2] = {
1390         "Print dialog based on callid and fromtag", 0
1391 };
1392 static const char *rpc_print_dlg_ctx_doc[2] = {
1393         "Print dialog with associated context based on callid and fromtag", 0
1394 };
1395 static const char *rpc_end_dlg_entry_id_doc[2] = {
1396         "End a given dialog based on [h_entry] [h_id]", 0
1397 };
1398 static const char *rpc_profile_get_size_doc[2] = {
1399         "Returns the number of dialogs belonging to a profile", 0
1400 };
1401 static const char *rpc_profile_print_dlgs_doc[2] = {
1402         "Lists all the dialogs belonging to a profile", 0
1403 };
1404 static const char *rpc_dlg_bridge_doc[2] = {
1405         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:\
1406  to, from, [outbound SIP proxy]", 0
1407 };
1408
1409
1410 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
1411         internal_rpc_print_dlgs(rpc, c, 0);
1412 }
1413 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
1414         internal_rpc_print_dlgs(rpc, c, 1);
1415 }
1416 static void rpc_print_dlg(rpc_t *rpc, void *c) {
1417         internal_rpc_print_single_dlg(rpc, c, 0);
1418 }
1419 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
1420         internal_rpc_print_single_dlg(rpc, c, 1);
1421 }
1422 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
1423         unsigned int h_entry, h_id;
1424         struct dlg_cell * dlg = NULL;
1425         str rpc_extra_hdrs = {NULL,0};
1426
1427         if (rpc->scan(c, "ddS", &h_entry, &h_id, &rpc_extra_hdrs) < 2) return;
1428
1429         dlg = lookup_dlg(h_entry, h_id, NULL);
1430         if(dlg){
1431                 dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
1432                 unref_dlg(dlg, 1);
1433         }
1434 }
1435 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
1436         str profile_name = {NULL,0};
1437         str value = {NULL,0};
1438
1439         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1440         if (rpc->scan(c, "*.S", &value) > 0) {
1441                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
1442         } else {
1443                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
1444         }
1445         return;
1446 }
1447 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
1448         str profile_name = {NULL,0};
1449         str value = {NULL,0};
1450
1451         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1452         if (rpc->scan(c, "*.S", &value) > 0) {
1453                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
1454         } else {
1455                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
1456         }
1457         return;
1458 }
1459 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
1460         str from = {NULL,0};
1461         str to = {NULL,0};
1462         str op = {NULL,0};
1463
1464         if (rpc->scan(c, "SSS", &from, &to, &op) < 2) return;
1465
1466         dlg_bridge(&from, &to, &op);
1467 }
1468
1469 static rpc_export_t rpc_methods[] = {
1470         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
1471         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, 0},
1472         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
1473         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
1474         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
1475         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
1476         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, 0},
1477         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
1478         {0, 0, 0, 0}
1479 };