modules_k/acc: Implement CDR-based logging.
[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->set_dlg_var = set_dlg_variable;
377         dlgb->get_dlg_var = get_dlg_variable;
378         return 1;
379 }
380
381
382 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
383                 pv_value_t *res)
384 {
385         int n;
386         int l;
387         char *ch;
388
389         if(msg==NULL || res==NULL)
390                 return -1;
391
392         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
393         l = 0;
394         ch = int2str( n, &l);
395
396         res->rs.s = ch;
397         res->rs.len = l;
398
399         res->ri = n;
400         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
401
402         return 0;
403 }
404
405
406 static int mod_init(void)
407 {
408         unsigned int n;
409
410
411 #ifdef STATISTICS
412         /* register statistics */
413         if (register_module_stats( exports.name, mod_stats)!=0 ) {
414                 LM_ERR("failed to register core statistics\n");
415                 return -1;
416         }
417 #endif
418
419         if(register_mi_mod(exports.name, mi_cmds)!=0)
420         {
421                 LM_ERR("failed to register MI commands\n");
422                 return -1;
423         }
424
425         if (rpc_register_array(rpc_methods)!=0) {
426                 LM_ERR("failed to register RPC commands\n");
427                 return -1;
428         }
429
430         if(faked_msg_init()<0)
431                 return -1;
432
433         if (timeout_spec.s)
434                 timeout_spec.len = strlen(timeout_spec.s);
435
436         dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
437         db_url.len = strlen(db_url.s);
438         call_id_column.len = strlen(call_id_column.s);
439         from_uri_column.len = strlen(from_uri_column.s);
440         from_tag_column.len = strlen(from_tag_column.s);
441         to_uri_column.len = strlen(to_uri_column.s);
442         to_tag_column.len = strlen(to_tag_column.s);
443         h_id_column.len = strlen(h_id_column.s);
444         h_entry_column.len = strlen(h_entry_column.s);
445         state_column.len = strlen(state_column.s);
446         start_time_column.len = strlen(start_time_column.s);
447         timeout_column.len = strlen(timeout_column.s);
448         to_cseq_column.len = strlen(to_cseq_column.s);
449         from_cseq_column.len = strlen(from_cseq_column.s);
450         to_route_column.len = strlen(to_route_column.s);
451         from_route_column.len = strlen(from_route_column.s);
452         to_contact_column.len = strlen(to_contact_column.s);
453         from_contact_column.len = strlen(from_contact_column.s);
454         to_sock_column.len = strlen(to_sock_column.s);
455         from_sock_column.len = strlen(from_sock_column.s);
456         sflags_column.len = strlen(sflags_column.s);
457         toroute_name_column.len = strlen(toroute_name_column.s);
458         dialog_table_name.len = strlen(dialog_table_name.s);
459
460         dialog_vars_table_name.len = strlen(dialog_vars_table_name.s);
461         vars_h_id_column.len = strlen(vars_h_id_column.s);
462         vars_h_entry_column.len = strlen(vars_h_entry_column.s);
463         vars_key_column.len = strlen(vars_key_column.s);
464         vars_value_column.len = strlen(vars_value_column.s);
465
466         /* param checkings */
467         if (dlg_flag==-1) {
468                 LM_ERR("no dlg flag set!!\n");
469                 return -1;
470         } else if (dlg_flag>MAX_FLAG) {
471                 LM_ERR("invalid dlg flag %d!!\n",dlg_flag);
472                 return -1;
473         }
474
475         if (rr_param==0 || rr_param[0]==0) {
476                 LM_ERR("empty rr_param!!\n");
477                 return -1;
478         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
479                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
480                 return -1;
481         }
482
483         if (timeout_spec.s) {
484                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 
485                                 && (timeout_avp.type!=PVT_AVP)){
486                         LM_ERR("malformed or non AVP timeout "
487                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
488                         return -1;
489                 }
490         }
491
492         if (default_timeout<=0) {
493                 LM_ERR("0 default_timeout not accepted!!\n");
494                 return -1;
495         }
496
497         if (ruri_pvar_param.s==NULL || *ruri_pvar_param.s=='\0') {
498                 LM_ERR("invalid r-uri PV string\n");
499                 return -1;
500         }
501         ruri_pvar_param.len = strlen(ruri_pvar_param.s);
502         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
503                                 || ruri_param_model==NULL) {
504                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
505                 return -1;
506         }
507
508         if (initial_cbs_inscript != 0 && initial_cbs_inscript != 1) {
509                 LM_ERR("invalid parameter for running initial callbacks in-script (must be either 0 or 1)\n");
510                 return -1;
511         }
512
513         /* update the len of the extra headers */
514         if (dlg_extra_hdrs.s)
515                 dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
516
517         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
518         seq_match_mode!=SEQ_MATCH_FALLBACK &&
519         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
520                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
521                 return -1;
522         }
523
524         if (detect_spirals != 0 && detect_spirals != 1) {
525                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
526                 return -1;
527         }
528
529         /* if statistics are disabled, prevent their registration to core */
530         if (dlg_enable_stats==0)
531                 exports.stats = 0;
532
533         /* create profile hashes */
534         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
535                 LM_ERR("failed to add profiles without value\n");
536                 return -1;
537         }
538         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
539                 LM_ERR("failed to add profiles with value\n");
540                 return -1;
541         }
542
543         /* load the TM API */
544         if (load_tm_api(&d_tmb)!=0) {
545                 LM_ERR("can't load TM API\n");
546                 return -1;
547         }
548
549         /* load RR API also */
550         if (load_rr_api(&d_rrb)!=0) {
551                 LM_ERR("can't load RR API\n");
552                 return -1;
553         }
554
555         /* register callbacks*/
556         /* listen for all incoming requests  */
557         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
558                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
559                 return -1;
560         }
561
562         /* listen for all routed requests  */
563         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
564                 LM_ERR("cannot register RR callback\n");
565                 return -1;
566         }
567
568         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
569                 LM_ERR("cannot regsiter script callback");
570                 return -1;
571         }
572         if (register_script_cb(dlg_cfg_cb,
573                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
574         {
575                 LM_ERR("cannot regsiter pre-script ctx callback\n");
576                 return -1;
577         }
578         if (register_script_cb(dlg_cfg_cb,
579                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
580         {
581                 LM_ERR("cannot regsiter post-script ctx callback\n");
582                 return -1;
583         }
584
585         if (register_script_cb( spiral_detect_reset, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
586                 LM_ERR("cannot register req pre-script spiral detection reset callback\n");
587                 return -1;
588         }
589
590         if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
591                 LM_ERR("failed to register timer \n");
592                 return -1;
593         }
594
595         /* init handlers */
596         init_dlg_handlers( rr_param, dlg_flag,
597                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
598
599         /* init timer */
600         if (init_dlg_timer(dlg_ontimeout)!=0) {
601                 LM_ERR("cannot init timer list\n");
602                 return -1;
603         }
604
605         /* initialized the hash table */
606         for( n=0 ; n<(8*sizeof(n)) ; n++) {
607                 if (dlg_hash_size==(1<<n))
608                         break;
609                 if (dlg_hash_size<(1<<n)) {
610                         LM_WARN("hash_size is not a power "
611                                 "of 2 as it should be -> rounding from %d to %d\n",
612                                 dlg_hash_size, 1<<(n-1));
613                         dlg_hash_size = 1<<(n-1);
614                 }
615         }
616
617         if ( init_dlg_table(dlg_hash_size)<0 ) {
618                 LM_ERR("failed to create hash table\n");
619                 return -1;
620         }
621
622         /* if a database should be used to store the dialogs' information */
623         dlg_db_mode = dlg_db_mode_param;
624         if (dlg_db_mode==DB_MODE_NONE) {
625                 db_url.s = 0; db_url.len = 0;
626         } else {
627                 if (dlg_db_mode!=DB_MODE_REALTIME &&
628                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
629                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
630                         return -1;
631                 }
632                 if ( !db_url.s || db_url.len==0 ) {
633                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
634                         return -1;
635                 }
636                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period,db_fetch_rows)!=0) {
637                         LM_ERR("failed to initialize the DB support\n");
638                         return -1;
639                 }
640                 run_load_callbacks();
641         }
642
643         destroy_dlg_callbacks( DLGCB_LOADED );
644
645         return 0;
646 }
647
648
649 static int child_init(int rank)
650 {
651         dlg_db_mode = dlg_db_mode_param;
652
653         if (rank==1) {
654                 if_update_stat(dlg_enable_stats, active_dlgs, active_dlgs_cnt);
655                 if_update_stat(dlg_enable_stats, early_dlgs, early_dlgs_cnt);
656         }
657
658         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
659         (rank>0 || rank==PROC_TIMER)) ||
660         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
661                 if ( dlg_connect_db(&db_url) ) {
662                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
663                         return -1;
664                 }
665         }
666
667         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
668          * for the rest of the processes will be the same as DB_MODE_NONE */
669         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
670                 dlg_db_mode = DB_MODE_NONE;
671         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
672         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
673                         rank==PROC_MAIN)
674                 dlg_db_mode = DB_MODE_NONE;
675
676         return 0;
677 }
678
679
680 static void mod_destroy(void)
681 {
682         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
683                 dialog_update_db(0, 0);
684                 destroy_dlg_db();
685         }
686         /* no DB interaction from now on */
687         dlg_db_mode = DB_MODE_NONE;
688         destroy_dlg_table();
689         destroy_dlg_timer();
690         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
691         destroy_dlg_handlers();
692         destroy_dlg_profiles();
693 }
694
695
696
697 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
698 {
699         pv_elem_t *pve;
700         str val_s;
701
702         pve = (pv_elem_t *)value;
703
704         if (((struct dlg_profile_table*)profile)->has_value) {
705                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
706                 val_s.len == 0 || val_s.s == NULL) {
707                         LM_WARN("cannot get string for value\n");
708                         return -1;
709                 }
710                 if ( set_dlg_profile( msg, &val_s,
711                 (struct dlg_profile_table*)profile) < 0 ) {
712                         LM_ERR("failed to set profile");
713                         return -1;
714                 }
715         } else {
716                 if ( set_dlg_profile( msg, NULL,
717                 (struct dlg_profile_table*)profile) < 0 ) {
718                         LM_ERR("failed to set profile");
719                         return -1;
720                 }
721         }
722         return 1;
723 }
724
725
726
727 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
728 {
729         pv_elem_t *pve;
730         str val_s;
731
732         pve = (pv_elem_t *)value;
733
734         if (((struct dlg_profile_table*)profile)->has_value) {
735                 if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || 
736                 val_s.len == 0 || val_s.s == NULL) {
737                         LM_WARN("cannot get string for value\n");
738                         return -1;
739                 }
740                 if ( unset_dlg_profile( msg, &val_s,
741                 (struct dlg_profile_table*)profile) < 0 ) {
742                         LM_ERR("failed to unset profile");
743                         return -1;
744                 }
745         } else {
746                 if ( unset_dlg_profile( msg, NULL,
747                 (struct dlg_profile_table*)profile) < 0 ) {
748                         LM_ERR("failed to unset profile");
749                         return -1;
750                 }
751         }
752         return 1;
753 }
754
755
756
757 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
758 {
759         pv_elem_t *pve;
760         str val_s;
761
762         pve = (pv_elem_t *)value;
763
764         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
765                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
766                 val_s.len == 0 || val_s.s == NULL) {
767                         LM_WARN("cannot get string for value\n");
768                         return -1;
769                 }
770                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
771                         &val_s);
772         } else {
773                 return is_dlg_in_profile( msg, (struct dlg_profile_table*)profile,
774                         NULL);
775         }
776 }
777
778
779 /**
780  * get dynamic name profile size
781  */
782 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
783                 char *value, char *result)
784 {
785         pv_elem_t *pve;
786         str val_s;
787         pv_spec_t *sp_dest;
788         unsigned int size;
789         pv_value_t val;
790
791         if(result!=NULL)
792         {
793                 pve = (pv_elem_t *)value;
794                 sp_dest = (pv_spec_t *)result;
795         } else {
796                 pve = NULL;
797                 sp_dest = (pv_spec_t *)value;
798         }
799         if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) {
800                 if ( pv_printf_s(msg, pve, &val_s)!=0 || 
801                 val_s.len == 0 || val_s.s == NULL) {
802                         LM_WARN("cannot get string for value\n");
803                         return -1;
804                 }
805                 size = get_profile_size( (struct dlg_profile_table*)profile, &val_s );
806         } else {
807                 size = get_profile_size( (struct dlg_profile_table*)profile, NULL );
808         }
809
810         memset(&val, 0, sizeof(pv_value_t));
811         val.flags = PV_VAL_INT|PV_TYPE_INT;
812         val.ri = (int)size;
813
814         if(sp_dest->setf(msg, &sp_dest->pvp, (int)EQ_T, &val)<0)
815         {
816                 LM_ERR("setting profile PV failed\n");
817                 return -1;
818         }
819
820         return 1;
821 }
822
823
824 /**
825  * get static name profile size
826  */
827 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
828 {
829         return w_get_profile_size3(msg, profile, result, NULL);
830 }
831
832
833 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
834 {
835         dlg_ctx_t *dctx;
836         int val;
837
838         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
839         {
840                 LM_ERR("no flag value\n");
841                 return -1;
842         }
843         if(val<0 || val>31)
844                 return -1;
845         if ( (dctx=dlg_get_dlg_ctx())==NULL )
846                 return -1;
847
848         dctx->flags |= 1<<val;
849         if(dctx->dlg)
850                 dctx->dlg->sflags |= 1<<val;
851         return 1;
852 }
853
854
855 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
856 {
857         dlg_ctx_t *dctx;
858         int val;
859
860         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
861         {
862                 LM_ERR("no flag value\n");
863                 return -1;
864         }
865         if(val<0 || val>31)
866                 return -1;
867
868         if ( (dctx=dlg_get_dlg_ctx())==NULL )
869                 return -1;
870
871         dctx->flags &= ~(1<<val);
872         if(dctx->dlg)
873                 dctx->dlg->sflags &= ~(1<<val);
874         return 1;
875 }
876
877
878 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
879 {
880         dlg_ctx_t *dctx;
881         int val;
882
883         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
884         {
885                 LM_ERR("no flag value\n");
886                 return -1;
887         }
888         if(val<0 || val>31)
889                 return -1;
890
891         if ( (dctx=dlg_get_dlg_ctx())==NULL )
892                 return -1;
893
894         if(dctx->dlg)
895                 return (dctx->dlg->sflags&(1<<val))?1:-1;
896         return (dctx->flags&(1<<val))?1:-1;
897 }
898
899 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
900 {
901         str tag;
902         int backup_mode;
903
904         if( (msg->to==NULL && parse_headers(msg, HDR_TO_F,0)<0) || msg->to==NULL )
905         {
906                 LM_ERR("bad TO header\n");
907                 return -1;
908         }
909         tag = get_to(msg)->tag_value;
910         if(tag.s!=0 && tag.len!=0)
911         {
912                 backup_mode = seq_match_mode;
913                 seq_match_mode = SEQ_MATCH_NO_ID;
914                 dlg_onroute(msg, NULL, NULL);
915                 seq_match_mode = backup_mode;
916         } else {
917                 if(dlg_new_dialog(msg, 0, initial_cbs_inscript)!=0)
918                         return -1;
919         }
920         return 1;
921 }
922
923 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
924 {
925         struct dlg_cell *dlg;
926         int n;
927
928         dlg = dlg_get_ctx_dialog();
929         if(dlg==NULL)
930                 return -1;
931         
932         n = (int)(long)side;
933         if(n==1)
934         {
935                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
936                         return -1;
937                 return 1;
938         } else if(n==2) {
939                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
940                         return -1;
941                 return 1;
942         } else {
943                 if(dlg_bye_all(dlg, NULL)!=0)
944                         return -1;
945                 return 1;
946         }
947 }
948
949 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
950 {
951         struct dlg_cell *dlg;
952         int n;
953         str st = {0,0};
954
955         dlg = dlg_get_ctx_dialog();
956         if(dlg==NULL)
957                 return -1;
958         
959         n = (int)(long)side;
960
961         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
962         {
963                 LM_ERR("unable to get To\n");
964                 return -1;
965         }
966         if(st.s==NULL || st.len == 0)
967         {
968                 LM_ERR("invalid To parameter\n");
969                 return -1;
970         }
971         if(n==1)
972         {
973                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
974                         return -1;
975         } else {
976                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
977                         return -1;
978         }
979         return 1;
980 }
981
982 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
983 {
984         str sf = {0,0};
985         str st = {0,0};
986         str so = {0,0};
987
988         if(from==0 || to==0 || op==0)
989         {
990                 LM_ERR("invalid parameters\n");
991                 return -1;
992         }
993
994         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
995         {
996                 LM_ERR("unable to get From\n");
997                 return -1;
998         }
999         if(sf.s==NULL || sf.len == 0)
1000         {
1001                 LM_ERR("invalid From parameter\n");
1002                 return -1;
1003         }
1004         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1005         {
1006                 LM_ERR("unable to get To\n");
1007                 return -1;
1008         }
1009         if(st.s==NULL || st.len == 0)
1010         {
1011                 LM_ERR("invalid To parameter\n");
1012                 return -1;
1013         }
1014         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
1015         {
1016                 LM_ERR("unable to get OP\n");
1017                 return -1;
1018         }
1019
1020         if(dlg_bridge(&sf, &st, &so)!=0)
1021                 return -1;
1022         return 1;
1023 }
1024
1025
1026 static int fixup_dlg_bye(void** param, int param_no)
1027 {
1028         char *val;
1029         int n = 0;
1030
1031         if (param_no==1) {
1032                 val = (char*)*param;
1033                 if (strcasecmp(val,"all")==0) {
1034                         n = 0;
1035                 } else if (strcasecmp(val,"caller")==0) {
1036                         n = 1;
1037                 } else if (strcasecmp(val,"callee")==0) {
1038                         n = 2;
1039                 } else {
1040                         LM_ERR("invalid param \"%s\"\n", val);
1041                         return E_CFG;
1042                 }
1043                 pkg_free(*param);
1044                 *param=(void*)(long)n;
1045         } else {
1046                 LM_ERR("called with parameter != 1\n");
1047                 return E_BUG;
1048         }
1049         return 0;
1050 }
1051
1052 static int fixup_dlg_refer(void** param, int param_no)
1053 {
1054         char *val;
1055         int n = 0;
1056
1057         if (param_no==1) {
1058                 val = (char*)*param;
1059                 if (strcasecmp(val,"caller")==0) {
1060                         n = 1;
1061                 } else if (strcasecmp(val,"callee")==0) {
1062                         n = 2;
1063                 } else {
1064                         LM_ERR("invalid param \"%s\"\n", val);
1065                         return E_CFG;
1066                 }
1067                 pkg_free(*param);
1068                 *param=(void*)(long)n;
1069         } else if (param_no==2) {
1070                 return fixup_spve_null(param, 1);
1071         } else {
1072                 LM_ERR("called with parameter idx %d\n", param_no);
1073                 return E_BUG;
1074         }
1075         return 0;
1076 }
1077
1078 static int fixup_dlg_bridge(void** param, int param_no)
1079 {
1080         if (param_no>=1 && param_no<=3) {
1081                 return fixup_spve_null(param, 1);
1082         } else {
1083                 LM_ERR("called with parameter idx %d\n", param_no);
1084                 return E_BUG;
1085         }
1086         return 0;
1087 }
1088
1089 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1090 {
1091         struct dlg_cell *dlg = NULL;
1092         str sc = {0,0};
1093         str sf = {0,0};
1094         str st = {0,0};
1095         unsigned int dir = 0;
1096
1097         if(ci==0 || ft==0 || tt==0)
1098         {
1099                 LM_ERR("invalid parameters\n");
1100                 return -1;
1101         }
1102
1103         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1104         {
1105                 LM_ERR("unable to get Call-ID\n");
1106                 return -1;
1107         }
1108         if(sc.s==NULL || sc.len == 0)
1109         {
1110                 LM_ERR("invalid Call-ID parameter\n");
1111                 return -1;
1112         }
1113         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1114         {
1115                 LM_ERR("unable to get From tag\n");
1116                 return -1;
1117         }
1118         if(sf.s==NULL || sf.len == 0)
1119         {
1120                 LM_ERR("invalid From tag parameter\n");
1121                 return -1;
1122         }
1123         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1124         {
1125                 LM_ERR("unable to get To Tag\n");
1126                 return -1;
1127         }
1128         if(st.s==NULL || st.len == 0)
1129         {
1130                 LM_ERR("invalid To tag parameter\n");
1131                 return -1;
1132         }
1133
1134         dlg = get_dlg(&sc, &sf, &st, &dir, NULL);
1135         if(dlg==NULL)
1136                 return -1;
1137         current_dlg_pointer = dlg;
1138         _dlg_ctx.dlg = dlg;
1139         _dlg_ctx.dir = dir;
1140         return 1;
1141 }
1142
1143 struct mi_root * mi_dlg_bridge(struct mi_root *cmd_tree, void *param)
1144 {
1145         str from = {0,0};
1146         str to = {0,0};
1147         str op = {0,0};
1148         struct mi_node* node;
1149
1150         node = cmd_tree->node.kids;
1151         if(node == NULL)
1152                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1153         from = node->value;
1154         if(from.len<=0 || from.s==NULL)
1155         {
1156                 LM_ERR("bad From value\n");
1157                 return init_mi_tree( 500, "Bad From value", 14);
1158         }
1159
1160         node = node->next;
1161         if(node == NULL)
1162                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
1163         to = node->value;
1164         if(to.len<=0 || to.s == NULL)
1165         {
1166                 return init_mi_tree(500, "Bad To value", 12);
1167         }
1168
1169         node= node->next;
1170         if(node != NULL)
1171         {
1172                 op = node->value;
1173                 if(op.len<=0 || op.s==NULL)
1174                 {
1175                         return init_mi_tree(500, "Bad OP value", 12);
1176                 }
1177         }
1178
1179         if(dlg_bridge(&from, &to, &op)!=0)
1180                 return init_mi_tree(500, MI_INTERNAL_ERR_S,  MI_INTERNAL_ERR_LEN);
1181
1182         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
1183 }
1184
1185 /**************************** RPC functions ******************************/
1186 /*!
1187  * \brief Helper method that outputs a dialog via the RPC interface
1188  * \see rpc_print_dlg
1189  * \param rpc RPC node that should be filled
1190  * \param c RPC void pointer
1191  * \param dlg printed dialog
1192  * \param with_context if 1 then the dialog context will be also printed
1193  * \return 0 on success, -1 on failure
1194  */
1195 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *dlg, int with_context)
1196 {
1197         rpc_cb_ctx_t rpc_cb;
1198
1199         rpc->printf(c, "hash:%u:%u state:%u timestart:%u timeout:%u",
1200                 dlg->h_entry, dlg->h_id, dlg->state, dlg->start_ts, dlg->tl.timeout);
1201         rpc->printf(c, "\tcallid:%.*s from_tag:%.*s to_tag:%.*s",
1202                 dlg->callid.len, dlg->callid.s,
1203                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
1204                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
1205         rpc->printf(c, "\tfrom_uri:%.*s to_uri:%.*s",
1206                 dlg->from_uri.len, dlg->from_uri.s, dlg->to_uri.len, dlg->to_uri.s);
1207         rpc->printf(c, "\tcaller_contact:%.*s caller_cseq:%.*s",
1208                 dlg->contact[DLG_CALLER_LEG].len, dlg->contact[DLG_CALLER_LEG].s,
1209                 dlg->cseq[DLG_CALLER_LEG].len, dlg->cseq[DLG_CALLER_LEG].s);
1210         rpc->printf(c, "\tcaller_route_set: %.*s",
1211                 dlg->route_set[DLG_CALLER_LEG].len, dlg->route_set[DLG_CALLER_LEG].s);
1212         rpc->printf(c, "\tcallee_contact:%.*s callee_cseq:%.*s",
1213                 dlg->contact[DLG_CALLEE_LEG].len, dlg->contact[DLG_CALLEE_LEG].s,
1214                 dlg->cseq[DLG_CALLEE_LEG].len, dlg->cseq[DLG_CALLEE_LEG].s);
1215         rpc->printf(c, "\tcallee_route_set: %.*s",
1216                 dlg->route_set[DLG_CALLEE_LEG].len, dlg->route_set[DLG_CALLEE_LEG].s);
1217         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
1218                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:%.*s",
1219                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
1220                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s);
1221         } else {
1222                 rpc->printf(c, "\tcaller_bind_addr:%.*s callee_bind_addr:",
1223                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len, dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s);
1224         }
1225         if (with_context) {
1226                 rpc_cb.rpc = rpc;
1227                 rpc_cb.c = c;
1228                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
1229         }
1230 }
1231
1232 /*!
1233  * \brief Helper function that outputs all dialogs via the RPC interface
1234  * \see rpc_print_dlgs
1235  * \param rpc RPC node that should be filled
1236  * \param c RPC void pointer
1237  * \param with_context if 1 then the dialog context will be also printed
1238  */
1239 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
1240 {
1241         struct dlg_cell *dlg;
1242         unsigned int i;
1243
1244         for( i=0 ; i<d_table->size ; i++ ) {
1245                 dlg_lock( d_table, &(d_table->entries[i]) );
1246
1247                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
1248                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1249                 }
1250                 dlg_unlock( d_table, &(d_table->entries[i]) );
1251         }
1252 }
1253
1254 /*!
1255  * \brief Helper function that outputs a dialog via the RPC interface
1256  * \see rpc_print_dlgs
1257  * \param rpc RPC node that should be filled
1258  * \param c RPC void pointer
1259  * \param with_context if 1 then the dialog context will be also printed
1260  */
1261 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
1262         str callid, from_tag;
1263         struct dlg_entry *d_entry;
1264         struct dlg_cell *dlg;
1265         unsigned int h_entry;
1266
1267         if (rpc->scan(c, ".S.S", &callid, &from_tag) < 2) return;
1268
1269         h_entry = core_hash( &callid, 0, d_table->size);
1270         d_entry = &(d_table->entries[h_entry]);
1271         dlg_lock( d_table, d_entry);
1272         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
1273                 if (match_downstream_dialog( dlg, &callid, &from_tag)==1) {
1274                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
1275                 }
1276         }
1277         dlg_unlock( d_table, d_entry);
1278 }
1279
1280 /*!
1281  * \brief Helper function that outputs the size of a given profile via the RPC interface
1282  * \see rpc_profile_get_size
1283  * \see rpc_profile_w_value_get_size
1284  * \param rpc RPC node that should be filled
1285  * \param c RPC void pointer
1286  * \param profile_name the given profile
1287  * \param value the given profile value
1288  */
1289 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name, str *value) {
1290         unsigned int size;
1291         struct dlg_profile_table *profile;
1292
1293         profile = search_dlg_profile( profile_name );
1294         if (!profile) {
1295                 rpc->printf(c, "Non existing profile:%.*s",
1296                         profile_name->len, profile_name->s);
1297                 return;
1298         }
1299         size = get_profile_size(profile, value);
1300         if (value) {
1301                 rpc->printf(c, "Profile:%.*s => profile:%.*s value:%.*s count:%u",
1302                         profile_name->len, profile_name->s,
1303                         profile->name.len, profile->name.s,
1304                         value->len, value->s, size);
1305                 return;
1306         } else {
1307                 rpc->printf(c, "Profile:%.*s => profile:%.*s value: count:%u",
1308                         profile_name->len, profile_name->s,
1309                         profile->name.len, profile->name.s, size);
1310                 return;
1311         }
1312         return;
1313 }
1314
1315 /*!
1316  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
1317  * \see rpc_profile_print_dlgs
1318  * \see rpc_profile_w_value_print_dlgs
1319  * \param rpc RPC node that should be filled
1320  * \param c RPC void pointer
1321  * \param profile_name the given profile
1322  * \param value the given profile value
1323  * \param with_context if 1 then the dialog context will be also printed
1324  */
1325 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name, str *value) {
1326         struct dlg_profile_table *profile;
1327         struct dlg_profile_hash *ph;
1328         unsigned int i;
1329
1330         profile = search_dlg_profile( profile_name );
1331         if (!profile) {
1332                 rpc->printf(c, "Non existing profile:%.*s",
1333                         profile_name->len, profile_name->s);
1334                 return;
1335         }
1336
1337         /* go through the hash and print the dialogs */
1338         if (profile->has_value==0 || value==NULL) {
1339                 /* no value */
1340                 lock_get( &profile->lock );
1341                 for ( i=0 ; i< profile->size ; i++ ) {
1342                         ph = profile->entries[i].first;
1343                         if(ph) {
1344                                 do {
1345                                         /* print dialog */
1346                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1347                                         /* next */
1348                                         ph=ph->next;
1349                                 }while(ph!=profile->entries[i].first);
1350                         }
1351                         lock_release(&profile->lock);
1352                 }
1353         } else {
1354                 /* check for value also */
1355                 lock_get( &profile->lock );
1356                 for ( i=0 ; i< profile->size ; i++ ) {
1357                         ph = profile->entries[i].first;
1358                         if(ph) {
1359                                 do {
1360                                         if ( value->len==ph->value.len &&
1361                                                 memcmp(value->s,ph->value.s,value->len)==0 ) {
1362                                                 /* print dialog */
1363                                                 internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
1364                                         }
1365                                         /* next */
1366                                         ph=ph->next;
1367                                 }while(ph!=profile->entries[i].first);
1368                         }
1369                         lock_release(&profile->lock);
1370                 }
1371         }
1372 }
1373
1374 /*
1375  * Wrapper around is_known_dlg().
1376  */
1377
1378 static int w_is_known_dlg(struct sip_msg *msg) {
1379         return  is_known_dlg(msg);
1380 }
1381
1382 static const char *rpc_print_dlgs_doc[2] = {
1383         "Print all dialogs", 0
1384 };
1385 static const char *rpc_print_dlgs_ctx_doc[2] = {
1386         "Print all dialogs with associated context", 0
1387 };
1388 static const char *rpc_print_dlg_doc[2] = {
1389         "Print dialog based on callid and fromtag", 0
1390 };
1391 static const char *rpc_print_dlg_ctx_doc[2] = {
1392         "Print dialog with associated context based on callid and fromtag", 0
1393 };
1394 static const char *rpc_end_dlg_entry_id_doc[2] = {
1395         "End a given dialog based on [h_entry] [h_id]", 0
1396 };
1397 static const char *rpc_profile_get_size_doc[2] = {
1398         "Returns the number of dialogs belonging to a profile", 0
1399 };
1400 static const char *rpc_profile_print_dlgs_doc[2] = {
1401         "Lists all the dialogs belonging to a profile", 0
1402 };
1403 static const char *rpc_dlg_bridge_doc[2] = {
1404         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:\
1405  to, from, [outbound SIP proxy]", 0
1406 };
1407
1408
1409 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
1410         internal_rpc_print_dlgs(rpc, c, 0);
1411 }
1412 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
1413         internal_rpc_print_dlgs(rpc, c, 1);
1414 }
1415 static void rpc_print_dlg(rpc_t *rpc, void *c) {
1416         internal_rpc_print_single_dlg(rpc, c, 0);
1417 }
1418 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
1419         internal_rpc_print_single_dlg(rpc, c, 1);
1420 }
1421 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
1422         unsigned int h_entry, h_id;
1423         struct dlg_cell * dlg = NULL;
1424         str rpc_extra_hdrs = {NULL,0};
1425
1426         if (rpc->scan(c, "ddS", &h_entry, &h_id, &rpc_extra_hdrs) < 2) return;
1427
1428         dlg = lookup_dlg(h_entry, h_id, NULL);
1429         if(dlg){
1430                 dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
1431                 unref_dlg(dlg, 1);
1432         }
1433 }
1434 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
1435         str profile_name = {NULL,0};
1436         str value = {NULL,0};
1437
1438         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1439         if (rpc->scan(c, "*.S", &value) > 0) {
1440                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
1441         } else {
1442                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
1443         }
1444         return;
1445 }
1446 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
1447         str profile_name = {NULL,0};
1448         str value = {NULL,0};
1449
1450         if (rpc->scan(c, ".S", &profile_name) < 1) return;
1451         if (rpc->scan(c, "*.S", &value) > 0) {
1452                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
1453         } else {
1454                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
1455         }
1456         return;
1457 }
1458 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
1459         str from = {NULL,0};
1460         str to = {NULL,0};
1461         str op = {NULL,0};
1462
1463         if (rpc->scan(c, "SSS", &from, &to, &op) < 2) return;
1464
1465         dlg_bridge(&from, &to, &op);
1466 }
1467
1468 static rpc_export_t rpc_methods[] = {
1469         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
1470         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, 0},
1471         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
1472         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
1473         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
1474         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
1475         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, 0},
1476         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
1477         {0, 0, 0, 0}
1478 };