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