dialog: export dlg_bridge() to kemi framework
[kamailio] / src / modules / dialog / dialog.c
1 /*
2  * dialog module - basic support for dialog tracking
3  *
4  * Copyright (C) 2006 Voice Sistem SRL
5  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
6  *
7  * This file is part of Kamailio, a free SIP server.
8  *
9  * Kamailio is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version
13  *
14  * Kamailio is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 /*!
26  * \file
27  * \brief Module interface
28  * \ingroup dialog
29  * Module: \ref dialog
30  */
31
32 /**
33  * @defgroup dialog dialog :: Kamailio dialog module
34  * @brief Kamailio dialog module
35  *
36  * The dialog module provides dialog awareness to the Kamailio proxy. Its
37  * functionality is to keep track of the current dialogs, to offer
38  * information about them (like how many dialogs are active) or to manage
39  * them. The module exports several functions that could be used directly
40  * from scripts.
41  * The module, via an internal API, also provide the foundation to build
42  * on top of it more complex dialog-based functionalities via other
43  * Kamailio modules.
44  */
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <sys/time.h>
50
51 #include "../../core/sr_module.h"
52 #include "../../lib/srdb1/db.h"
53 #include "../../core/dprint.h"
54 #include "../../core/error.h"
55 #include "../../core/ut.h"
56 #include "../../core/pvar.h"
57 #include "../../core/mod_fix.h"
58 #include "../../core/script_cb.h"
59 #include "../../core/kemi.h"
60 #include "../../core/fmsg.h"
61 #include "../../core/hashes.h"
62 #include "../../core/counters.h"
63 #include "../../core/mem/mem.h"
64 #include "../../core/timer_proc.h"
65 #include "../../core/lvalue.h"
66 #include "../../core/globals.h"
67 #include "../../core/parser/parse_to.h"
68 #include "../../modules/tm/tm_load.h"
69 #include "../../core/rpc_lookup.h"
70 #include "../../core/srapi.h"
71 #include "../rr/api.h"
72 #include "dlg_hash.h"
73 #include "dlg_timer.h"
74 #include "dlg_handlers.h"
75 #include "dlg_load.h"
76 #include "dlg_cb.h"
77 #include "dlg_db_handler.h"
78 #include "dlg_req_within.h"
79 #include "dlg_profile.h"
80 #include "dlg_var.h"
81 #include "dlg_transfer.h"
82 #include "dlg_cseq.h"
83 #include "dlg_dmq.h"
84
85 MODULE_VERSION
86
87
88 #define RPC_DATE_BUF_LEN 21
89
90 static int mod_init(void);
91 static int child_init(int rank);
92 static void mod_destroy(void);
93
94 /* module parameter */
95 static int dlg_hash_size = 4096;
96 static char* rr_param = "did";
97 static int dlg_flag = -1;
98 static str timeout_spec = {NULL, 0};
99 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
100 static int seq_match_mode = SEQ_MATCH_STRICT_ID;
101 static char* profiles_wv_s = NULL;
102 static char* profiles_nv_s = NULL;
103 str dlg_extra_hdrs = {NULL,0};
104 static int db_fetch_rows = 200;
105 static int db_skip_load = 0;
106 static int dlg_keep_proxy_rr = 0;
107 int initial_cbs_inscript = 1;
108 int dlg_wait_ack = 1;
109 static int dlg_timer_procs = 0;
110 static int _dlg_track_cseq_updates = 0;
111 int dlg_ka_failed_limit = 1;
112 int dlg_early_timeout = 300;
113 int dlg_noack_timeout = 60;
114 int dlg_end_timeout = 300;
115
116 int dlg_enable_dmq = 0;
117
118 int dlg_event_rt[DLG_EVENTRT_MAX];
119 str dlg_event_callback = STR_NULL;
120
121 str dlg_bridge_controller = str_init("sip:controller@kamailio.org");
122
123 str dlg_bridge_contact = str_init("sip:controller@kamailio.org:5060");
124
125 str ruri_pvar_param = str_init("$ru");
126 pv_elem_t * ruri_param_model = NULL;
127 str empty_str = STR_NULL;
128
129 int dlg_h_id_start = 0;
130 int dlg_h_id_step = 1;
131
132 /* statistic variables */
133 int dlg_enable_stats = 1;
134 int detect_spirals = 1;
135 int dlg_send_bye = 0;
136 int dlg_timeout_noreset = 0;
137 stat_var *active_dlgs = 0;
138 stat_var *processed_dlgs = 0;
139 stat_var *expired_dlgs = 0;
140 stat_var *failed_dlgs = 0;
141 stat_var *early_dlgs  = 0;
142
143 struct tm_binds d_tmb;
144 struct rr_binds d_rrb;
145 pv_spec_t timeout_avp;
146
147 int dlg_db_mode_param = DB_MODE_NONE;
148
149 str dlg_xavp_cfg = {0};
150 int dlg_ka_timer = 0;
151 int dlg_ka_interval = 0;
152 int dlg_clean_timer = 90;
153
154 str dlg_lreq_callee_headers = {0};
155
156 /* db stuff */
157 static str db_url = str_init(DEFAULT_DB_URL);
158 static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
159
160 static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param,
161                 pv_value_t *res);
162
163 void dlg_ka_timer_exec(unsigned int ticks, void* param);
164 void dlg_clean_timer_exec(unsigned int ticks, void* param);
165
166 /* commands wrappers and fixups */
167 static int fixup_profile(void** param, int param_no);
168 static int fixup_get_profile2(void** param, int param_no);
169 static int fixup_get_profile3(void** param, int param_no);
170 static int w_set_dlg_profile(struct sip_msg*, char*, char*);
171 static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
172 static int w_is_in_profile(struct sip_msg*, char*, char*);
173 static int w_get_profile_size2(struct sip_msg*, char*, char*);
174 static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
175 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
176 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
177 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
178 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2);
179 static int w_dlg_manage(struct sip_msg*, char*, char*);
180 static int w_dlg_bye(struct sip_msg*, char*, char*);
181 static int w_dlg_refer(struct sip_msg*, char*, char*);
182 static int w_dlg_bridge(struct sip_msg*, char*, char*, char*);
183 static int w_dlg_set_timeout(struct sip_msg*, char*, char*, char*);
184 static int w_dlg_set_timeout_by_profile2(struct sip_msg *, char *, char *);
185 static int w_dlg_set_timeout_by_profile3(struct sip_msg *, char *, char *,
186                                         char *);
187 static int fixup_dlg_bye(void** param, int param_no);
188 static int fixup_dlg_refer(void** param, int param_no);
189 static int fixup_dlg_bridge(void** param, int param_no);
190 static int w_dlg_get(struct sip_msg*, char*, char*, char*);
191 static int w_is_known_dlg(struct sip_msg *);
192 static int w_dlg_set_ruri(sip_msg_t *, char *, char *);
193 static int w_dlg_db_load_callid(sip_msg_t *msg, char *ci, char *p2);
194 static int w_dlg_db_load_extra(sip_msg_t *msg, char *p1, char *p2);
195
196 static int w_dlg_remote_profile(sip_msg_t *msg, char *cmd, char *pname,
197                 char *pval, char *puid, char *expires);
198 static int fixup_dlg_remote_profile(void** param, int param_no);
199
200 static cmd_export_t cmds[]={
201         {"dlg_manage", (cmd_function)w_dlg_manage,            0,0,
202                         0, REQUEST_ROUTE },
203         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  1,fixup_profile,
204                         0, ANY_ROUTE },
205         {"set_dlg_profile", (cmd_function)w_set_dlg_profile,  2,fixup_profile,
206                         0, ANY_ROUTE },
207         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  1,fixup_profile,
208                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
209         {"unset_dlg_profile", (cmd_function)w_unset_dlg_profile,  2,fixup_profile,
210                         0, REQUEST_ROUTE| FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE },
211         {"is_in_profile", (cmd_function)w_is_in_profile,      1,fixup_profile,
212                         0, ANY_ROUTE },
213         {"is_in_profile", (cmd_function)w_is_in_profile,      2,fixup_profile,
214                         0, ANY_ROUTE },
215         {"get_profile_size",(cmd_function)w_get_profile_size2, 2,fixup_get_profile2,
216                         0, ANY_ROUTE },
217         {"get_profile_size",(cmd_function)w_get_profile_size3, 3,fixup_get_profile3,
218                         0, ANY_ROUTE },
219         {"dlg_setflag", (cmd_function)w_dlg_setflag,          1,fixup_igp_null,
220                         0, ANY_ROUTE },
221         {"dlg_resetflag", (cmd_function)w_dlg_resetflag,      1,fixup_igp_null,
222                         0, ANY_ROUTE },
223         {"dlg_isflagset", (cmd_function)w_dlg_isflagset,      1,fixup_igp_null,
224                         0, ANY_ROUTE },
225         {"dlg_bye",(cmd_function)w_dlg_bye,                   1,fixup_dlg_bye,
226                         0, ANY_ROUTE },
227         {"dlg_refer",(cmd_function)w_dlg_refer,               2,fixup_dlg_refer,
228                         0, ANY_ROUTE },
229         {"dlg_bridge",(cmd_function)w_dlg_bridge,             3,fixup_dlg_bridge,
230                         0, ANY_ROUTE },
231         {"dlg_get",(cmd_function)w_dlg_get,                   3,fixup_dlg_bridge,
232                         0, ANY_ROUTE },
233         {"is_known_dlg", (cmd_function)w_is_known_dlg,        0, NULL,
234                         0, ANY_ROUTE },
235         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  1,fixup_igp_null,
236                         0, ANY_ROUTE },
237         {"dlg_set_timeout", (cmd_function)w_dlg_set_timeout,  3,fixup_igp_all,
238                         0, ANY_ROUTE },
239         {"dlg_set_timeout_by_profile",
240                 (cmd_function) w_dlg_set_timeout_by_profile2, 2, fixup_profile,
241                         0, ANY_ROUTE },
242         {"dlg_set_timeout_by_profile",
243                 (cmd_function) w_dlg_set_timeout_by_profile3, 3, fixup_profile,
244                         0, ANY_ROUTE },
245         {"dlg_set_property", (cmd_function)w_dlg_set_property,1,fixup_spve_null,
246                         0, ANY_ROUTE },
247         {"dlg_remote_profile", (cmd_function)w_dlg_remote_profile, 5, fixup_dlg_remote_profile,
248                         0, ANY_ROUTE },
249         {"dlg_set_ruri",       (cmd_function)w_dlg_set_ruri,  0, NULL,
250                         0, ANY_ROUTE },
251         {"dlg_db_load_callid", (cmd_function)w_dlg_db_load_callid, 1, fixup_spve_null,
252                         0, ANY_ROUTE },
253         {"dlg_db_load_extra", (cmd_function)w_dlg_db_load_extra, 0, 0,
254                         0, ANY_ROUTE },
255
256         {"load_dlg",  (cmd_function)load_dlg,   0, 0, 0, 0},
257         {0,0,0,0,0,0}
258 };
259
260 static param_export_t mod_params[]={
261         { "enable_stats",          INT_PARAM, &dlg_enable_stats         },
262         { "hash_size",             INT_PARAM, &dlg_hash_size            },
263         { "rr_param",              PARAM_STRING, &rr_param                 },
264         { "dlg_flag",              INT_PARAM, &dlg_flag                 },
265         { "timeout_avp",           PARAM_STR, &timeout_spec           },
266         { "default_timeout",       INT_PARAM, &default_timeout          },
267         { "dlg_extra_hdrs",        PARAM_STR, &dlg_extra_hdrs         },
268         { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
269         { "detect_spirals",        INT_PARAM, &detect_spirals,          },
270         { "db_url",                PARAM_STR, &db_url                 },
271         { "db_mode",               INT_PARAM, &dlg_db_mode_param        },
272         { "table_name",            PARAM_STR, &dialog_table_name        },
273         { "call_id_column",        PARAM_STR, &call_id_column         },
274         { "from_uri_column",       PARAM_STR, &from_uri_column        },
275         { "from_tag_column",       PARAM_STR, &from_tag_column        },
276         { "to_uri_column",         PARAM_STR, &to_uri_column          },
277         { "to_tag_column",         PARAM_STR, &to_tag_column          },
278         { "h_id_column",           PARAM_STR, &h_id_column            },
279         { "h_entry_column",        PARAM_STR, &h_entry_column         },
280         { "state_column",          PARAM_STR, &state_column           },
281         { "start_time_column",     PARAM_STR, &start_time_column      },
282         { "timeout_column",        PARAM_STR, &timeout_column         },
283         { "to_cseq_column",        PARAM_STR, &to_cseq_column         },
284         { "from_cseq_column",      PARAM_STR, &from_cseq_column       },
285         { "to_route_column",       PARAM_STR, &to_route_column        },
286         { "from_route_column",     PARAM_STR, &from_route_column      },
287         { "to_contact_column",     PARAM_STR, &to_contact_column      },
288         { "from_contact_column",   PARAM_STR, &from_contact_column    },
289         { "to_sock_column",        PARAM_STR, &to_sock_column         },
290         { "from_sock_column",      PARAM_STR, &from_sock_column       },
291         { "sflags_column",         PARAM_STR, &sflags_column          },
292         { "toroute_name_column",   PARAM_STR, &toroute_name_column    },
293
294         { "vars_table_name",       PARAM_STR, &dialog_vars_table_name   },
295         { "vars_h_id_column",      PARAM_STR, &vars_h_id_column       },
296         { "vars_h_entry_column",   PARAM_STR, &vars_h_entry_column    },
297         { "vars_key_column",       PARAM_STR, &vars_key_column        },
298         { "vars_value_column",     PARAM_STR, &vars_value_column      },
299
300         { "db_update_period",      INT_PARAM, &db_update_period         },
301         { "db_fetch_rows",         INT_PARAM, &db_fetch_rows            },
302         { "profiles_with_value",   PARAM_STRING, &profiles_wv_s            },
303         { "profiles_no_value",     PARAM_STRING, &profiles_nv_s            },
304         { "bridge_controller",     PARAM_STR, &dlg_bridge_controller  },
305         { "bridge_contact",        PARAM_STR, &dlg_bridge_contact       },
306         { "ruri_pvar",             PARAM_STR, &ruri_pvar_param        },
307         { "initial_cbs_inscript",  INT_PARAM, &initial_cbs_inscript     },
308         { "send_bye",              INT_PARAM, &dlg_send_bye             },
309         { "wait_ack",              INT_PARAM, &dlg_wait_ack             },
310         { "xavp_cfg",              PARAM_STR, &dlg_xavp_cfg           },
311         { "ka_timer",              INT_PARAM, &dlg_ka_timer             },
312         { "ka_interval",           INT_PARAM, &dlg_ka_interval          },
313         { "timeout_noreset",       INT_PARAM, &dlg_timeout_noreset      },
314         { "timer_procs",           PARAM_INT, &dlg_timer_procs          },
315         { "track_cseq_updates",    PARAM_INT, &_dlg_track_cseq_updates  },
316         { "lreq_callee_headers",   PARAM_STR, &dlg_lreq_callee_headers  },
317         { "db_skip_load",          INT_PARAM, &db_skip_load             },
318         { "ka_failed_limit",       INT_PARAM, &dlg_ka_failed_limit      },
319         { "enable_dmq",            INT_PARAM, &dlg_enable_dmq           },
320         { "event_callback",        PARAM_STR, &dlg_event_callback       },
321         { "early_timeout",         PARAM_INT, &dlg_early_timeout        },
322         { "noack_timeout",         PARAM_INT, &dlg_noack_timeout        },
323         { "end_timeout",           PARAM_INT, &dlg_end_timeout          },
324         { "h_id_start",            PARAM_INT, &dlg_h_id_start           },
325         { "h_id_step",             PARAM_INT, &dlg_h_id_step            },
326         { "keep_proxy_rr",         INT_PARAM, &dlg_keep_proxy_rr        },
327         { 0,0,0 }
328 };
329
330
331 static stat_export_t mod_stats[] = {
332         {"active_dialogs" ,     STAT_NO_RESET,  &active_dlgs       },
333         {"early_dialogs",       STAT_NO_RESET,  &early_dlgs        },
334         {"processed_dialogs" ,  0,              &processed_dlgs    },
335         {"expired_dialogs" ,    0,              &expired_dlgs      },
336         {"failed_dialogs",      0,              &failed_dlgs       },
337         {0,0,0}
338 };
339
340 static rpc_export_t rpc_methods[];
341
342 static pv_export_t mod_items[] = {
343         { {"DLG_count",  sizeof("DLG_count")-1}, PVT_OTHER,  pv_get_dlg_count,    0,
344                 0, 0, 0, 0 },
345         { {"DLG_lifetime",sizeof("DLG_lifetime")-1}, PVT_OTHER, pv_get_dlg_lifetime, 0,
346                 0, 0, 0, 0 },
347         { {"DLG_status",  sizeof("DLG_status")-1}, PVT_OTHER, pv_get_dlg_status, 0,
348                 0, 0, 0, 0 },
349         { {"dlg_ctx",  sizeof("dlg_ctx")-1}, PVT_OTHER, pv_get_dlg_ctx,
350                 pv_set_dlg_ctx, pv_parse_dlg_ctx_name, 0, 0, 0 },
351         { {"dlg",  sizeof("dlg")-1}, PVT_OTHER, pv_get_dlg,
352                 0, pv_parse_dlg_name, 0, 0, 0 },
353         { {"dlg_var", sizeof("dlg_var")-1}, PVT_OTHER, pv_get_dlg_variable,
354                 pv_set_dlg_variable,    pv_parse_dialog_var_name, 0, 0, 0},
355         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
356 };
357
358 struct module_exports exports= {
359         "dialog",        /* module's name */
360         DEFAULT_DLFLAGS, /* dlopen flags */
361         cmds,            /* exported functions */
362         mod_params,      /* param exports */
363         0,               /* exported RPC methods */
364         mod_items,       /* exported pseudo-variables */
365         0,               /* reply processing function */
366         mod_init,        /* module initialization function */
367         child_init,      /* per-child init function */
368         mod_destroy
369 };
370
371
372 static int fixup_profile(void** param, int param_no)
373 {
374         struct dlg_profile_table *profile;
375         pv_elem_t *model=NULL;
376         str s;
377
378         s.s = (char*)(*param);
379         s.len = strlen(s.s);
380         if(s.len==0) {
381                 LM_ERR("param %d is empty string!\n", param_no);
382                 return E_CFG;
383         }
384
385         if (param_no==1) {
386                 profile = search_dlg_profile( &s );
387                 if (profile==NULL) {
388                         LM_CRIT("profile <%s> not defined\n",s.s);
389                         return E_CFG;
390                 }
391                 pkg_free(*param);
392                 *param = (void*)profile;
393                 return 0;
394         } else if (param_no==2) {
395                 if(pv_parse_format(&s ,&model) || model==NULL) {
396                         LM_ERR("wrong format [%s] for value param!\n", s.s);
397                         return E_CFG;
398                 }
399                 *param = (void*)model;
400         }
401         return 0;
402 }
403
404
405 static int fixup_get_profile2(void** param, int param_no)
406 {
407         pv_spec_t *sp;
408         int ret;
409
410         if (param_no==1) {
411                 return fixup_profile(param, 1);
412         } else if (param_no==2) {
413                 ret = fixup_pvar_null(param, 1);
414                 if (ret<0) return ret;
415                 sp = (pv_spec_t*)(*param);
416                 if (sp->type!=PVT_AVP && sp->type!=PVT_SCRIPTVAR) {
417                         LM_ERR("return must be an AVP or SCRIPT VAR!\n");
418                         return E_SCRIPT;
419                 }
420         }
421         return 0;
422 }
423
424
425 static int fixup_get_profile3(void** param, int param_no)
426 {
427         if (param_no==1) {
428                 return fixup_profile(param, 1);
429         } else if (param_no==2) {
430                 return fixup_profile(param, 2);
431         } else if (param_no==3) {
432                 return fixup_get_profile2( param, 2);
433         }
434         return 0;
435 }
436
437
438
439 int load_dlg( struct dlg_binds *dlgb )
440 {
441         dlgb->register_dlgcb = register_dlgcb;
442         dlgb->terminate_dlg = dlg_bye_all;
443         dlgb->set_dlg_var = set_dlg_variable;
444         dlgb->get_dlg_var = get_dlg_variable;
445         dlgb->get_dlg = dlg_get_msg_dialog;
446         dlgb->release_dlg = dlg_release;
447         return 1;
448 }
449
450
451 static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param,
452                 pv_value_t *res)
453 {
454         int n;
455         int l;
456         char *ch;
457
458         if(msg==NULL || res==NULL)
459                 return -1;
460
461         n = active_dlgs ? get_stat_val(active_dlgs) : 0;
462         l = 0;
463         ch = int2str( n, &l);
464
465         res->rs.s = ch;
466         res->rs.len = l;
467
468         res->ri = n;
469         res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
470
471         return 0;
472 }
473
474
475 static int mod_init(void)
476 {
477         unsigned int n;
478         sr_cfgenv_t *cenv = NULL;
479
480         if(dlg_h_id_start==-1) {
481                 dlg_h_id_start = server_id;
482         } else if(dlg_h_id_start<0) {
483                 dlg_h_id_start = 0;
484         }
485
486         if(dlg_h_id_step<1) {
487                 dlg_h_id_step = 1;
488         }
489
490         if(dlg_ka_interval!=0 && dlg_ka_interval<30) {
491                 LM_ERR("ka interval too low (%d), has to be at least 30\n",
492                                 dlg_ka_interval);
493                 return -1;
494         }
495
496         dlg_event_rt[DLG_EVENTRT_START] = route_lookup(&event_rt, "dialog:start");
497         dlg_event_rt[DLG_EVENTRT_END] = route_lookup(&event_rt, "dialog:end");
498         dlg_event_rt[DLG_EVENTRT_FAILED] = route_lookup(&event_rt, "dialog:failed");
499
500 #ifdef STATISTICS
501         /* register statistics */
502         if (dlg_enable_stats && (register_module_stats( exports.name, mod_stats)!=0 )) {
503                 LM_ERR("failed to register %s statistics\n", exports.name);
504                 return -1;
505         }
506 #endif
507
508         if (rpc_register_array(rpc_methods)!=0) {
509                 LM_ERR("failed to register RPC commands\n");
510                 return -1;
511         }
512
513         if(faked_msg_init()<0)
514                 return -1;
515
516         if(dlg_bridge_init_hdrs()<0)
517                 return -1;
518
519         /* param checkings */
520         if (dlg_flag!=-1 && dlg_flag>MAX_FLAG) {
521                 LM_ERR("invalid dlg flag %d!!\n", dlg_flag);
522                 return -1;
523         }
524
525         if (rr_param==0 || rr_param[0]==0) {
526                 LM_ERR("empty rr_param!!\n");
527                 return -1;
528         } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) {
529                 LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
530                 return -1;
531         }
532
533         if (dlg_keep_proxy_rr < 0 || dlg_keep_proxy_rr > 3) {
534                 LM_ERR("invalid value for keep_proxy_rr\n");
535                 return -1;
536         }
537
538         if (timeout_spec.s) {
539                 if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0
540                                 && (timeout_avp.type!=PVT_AVP)){
541                         LM_ERR("malformed or non AVP timeout "
542                                 "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s);
543                         return -1;
544                 }
545         }
546
547         if (default_timeout<=0) {
548                 LM_ERR("0 default_timeout not accepted!!\n");
549                 return -1;
550         }
551
552         if (ruri_pvar_param.s==NULL || ruri_pvar_param.len<=0) {
553                 LM_ERR("invalid r-uri PV string\n");
554                 return -1;
555         }
556
557         if(pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
558                                 || ruri_param_model==NULL) {
559                 LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
560                 return -1;
561         }
562
563         if (initial_cbs_inscript != 0 && initial_cbs_inscript != 1) {
564                 LM_ERR("invalid parameter for running initial callbacks in-script"
565                                 " (must be either 0 or 1)\n");
566                 return -1;
567         }
568
569         if (seq_match_mode!=SEQ_MATCH_NO_ID &&
570         seq_match_mode!=SEQ_MATCH_FALLBACK &&
571         seq_match_mode!=SEQ_MATCH_STRICT_ID ) {
572                 LM_ERR("invalid value %d for seq_match_mode param!!\n",seq_match_mode);
573                 return -1;
574         }
575
576         if (detect_spirals != 0 && detect_spirals != 1) {
577                 LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
578                 return -1;
579         }
580
581         if (dlg_timeout_noreset != 0 && dlg_timeout_noreset != 1) {
582                 LM_ERR("invalid value %d for timeout_noreset param!!\n",
583                                 dlg_timeout_noreset);
584                 return -1;
585         }
586
587         /* create profile hashes */
588         if (add_profile_definitions( profiles_nv_s, 0)!=0 ) {
589                 LM_ERR("failed to add profiles without value\n");
590                 return -1;
591         }
592         if (add_profile_definitions( profiles_wv_s, 1)!=0 ) {
593                 LM_ERR("failed to add profiles with value\n");
594                 return -1;
595         }
596
597         /* load the TM API */
598         if (load_tm_api(&d_tmb)!=0) {
599                 LM_ERR("can't load TM API\n");
600                 return -1;
601         }
602
603         /* load RR API also */
604         if (load_rr_api(&d_rrb)!=0) {
605                 LM_ERR("can't load RR API\n");
606                 return -1;
607         }
608
609         /* register callbacks*/
610         /* listen for all incoming requests  */
611         if ( d_tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0 ) <=0 ) {
612                 LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
613                 return -1;
614         }
615
616         /* listen for all routed requests  */
617         if ( d_rrb.register_rrcb( dlg_onroute, 0 ) <0 ) {
618                 LM_ERR("cannot register RR callback\n");
619                 return -1;
620         }
621
622         if (register_script_cb( profile_cleanup, POST_SCRIPT_CB|REQUEST_CB,0)<0) {
623                 LM_ERR("cannot register script callback");
624                 return -1;
625         }
626         if (register_script_cb(dlg_cfg_cb,
627                                 PRE_SCRIPT_CB|REQUEST_CB,0)<0)
628         {
629                 LM_ERR("cannot register pre-script ctx callback\n");
630                 return -1;
631         }
632         if (register_script_cb(dlg_cfg_cb,
633                                 POST_SCRIPT_CB|REQUEST_CB,0)<0)
634         {
635                 LM_ERR("cannot register post-script ctx callback\n");
636                 return -1;
637         }
638
639         if (register_script_cb(spiral_detect_reset,POST_SCRIPT_CB|REQUEST_CB,0)<0) {
640                 LM_ERR("cannot register req pre-script spiral detection reset callback\n");
641                 return -1;
642         }
643
644         if (register_script_cb(cb_dlg_locals_reset,POST_SCRIPT_CB|ONREPLY_CB,0)<0) {
645                 LM_ERR("cannot register reply post-script dlg locals reset callback\n");
646                 return -1;
647         }
648
649         if (register_script_cb(cb_dlg_locals_reset,POST_SCRIPT_CB|FAILURE_CB,0)<0) {
650                 LM_ERR("cannot register failure post-script dlg locals reset callback\n");
651                 return -1;
652         }
653
654         if(dlg_timer_procs<=0) {
655                 if ( register_timer( dlg_timer_routine, 0, 1)<0 ) {
656                         LM_ERR("failed to register timer \n");
657                         return -1;
658                 }
659         } else {
660                 register_sync_timers(1);
661         }
662
663         /* init handlers */
664         init_dlg_handlers( rr_param, dlg_flag,
665                 timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode, dlg_keep_proxy_rr);
666
667         /* init timer */
668         if (init_dlg_timer(dlg_ontimeout)!=0) {
669                 LM_ERR("cannot init timer list\n");
670                 return -1;
671         }
672
673         /* sanitize dlg_hash_zie */
674         if (dlg_hash_size < 1){
675                 LM_WARN("hash_size is smaller "
676                                 "then 1  -> rounding from %d to 1\n",
677                                 dlg_hash_size);
678                 dlg_hash_size = 1;
679         }
680         /* initialized the hash table */
681         for( n=0 ; n<(8*sizeof(n)) ; n++) {
682                 if (dlg_hash_size==(1<<n))
683                         break;
684                 if (n && dlg_hash_size<(1<<n)) {
685                         LM_WARN("hash_size is not a power "
686                                 "of 2 as it should be -> rounding from %d to %d\n",
687                                 dlg_hash_size, 1<<(n-1));
688                         dlg_hash_size = 1<<(n-1);
689                 }
690         }
691
692         if ( init_dlg_table(dlg_hash_size)<0 ) {
693                 LM_ERR("failed to create hash table\n");
694                 return -1;
695         }
696
697         /* if a database should be used to store the dialogs' information */
698         dlg_db_mode = dlg_db_mode_param;
699         if (dlg_db_mode==DB_MODE_NONE) {
700                 db_url.s = 0; db_url.len = 0;
701         } else {
702                 if (dlg_db_mode!=DB_MODE_REALTIME &&
703                 dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
704                         LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
705                         return -1;
706                 }
707                 if ( !db_url.s || db_url.len==0 ) {
708                         LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
709                         return -1;
710                 }
711                 if (init_dlg_db(&db_url, dlg_hash_size, db_update_period, db_fetch_rows, db_skip_load)!=0) {
712                         LM_ERR("failed to initialize the DB support\n");
713                         return -1;
714                 }
715         }
716
717         destroy_dlg_callbacks( DLGCB_LOADED );
718
719         /* timer process to send keep alive requests */
720         if(dlg_ka_timer>0 && dlg_ka_interval>0)
721                 register_sync_timers(1);
722
723         /* timer process to clean old unconfirmed dialogs */
724         register_sync_timers(1);
725
726         if(_dlg_track_cseq_updates!=0) {
727                 cenv = sr_cfgenv_get();
728                 cenv->cb_cseq_update = dlg_cseq_update;
729                 dlg_register_cseq_callbacks();
730         }
731
732         if (dlg_enable_dmq>0 && dlg_dmq_initialize()!=0) {
733                 LM_ERR("failed to initialize dmq integration\n");
734                 return -1;
735         }
736
737         return 0;
738 }
739
740
741 static int child_init(int rank)
742 {
743         dlg_db_mode = dlg_db_mode_param;
744
745
746         if(rank==PROC_INIT) {
747                 if (dlg_db_mode!=DB_MODE_NONE) {
748                         run_load_callbacks();
749                 }
750         }
751
752         if(rank==PROC_MAIN) {
753                 if(dlg_timer_procs>0) {
754                         if(fork_sync_timer(PROC_TIMER, "Dialog Main Timer", 1 /*socks flag*/,
755                                         dlg_timer_routine, NULL, 1 /*every sec*/)<0) {
756                                 LM_ERR("failed to start main timer routine as process\n");
757                                 return -1; /* error */
758                         }
759                 }
760
761                 if(dlg_ka_timer>0 && dlg_ka_interval>0) {
762                         if(fork_sync_timer(PROC_TIMER, "Dialog KA Timer", 1 /*socks flag*/,
763                                         dlg_ka_timer_exec, NULL, dlg_ka_timer /*sec*/)<0) {
764                                 LM_ERR("failed to start ka timer routine as process\n");
765                                 return -1; /* error */
766                         }
767                 }
768
769                 if(fork_sync_timer(PROC_TIMER, "Dialog Clean Timer", 1 /*socks flag*/,
770                                         dlg_clean_timer_exec, NULL, dlg_clean_timer /*sec*/)<0) {
771                         LM_ERR("failed to start clean timer routine as process\n");
772                         return -1; /* error */
773                 }
774         }
775
776         if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
777         (rank>0 || rank==PROC_TIMER || rank==PROC_RPC)) ||
778         (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
779                 if ( dlg_connect_db(&db_url) ) {
780                         LM_ERR("failed to connect to database (rank=%d)\n",rank);
781                         return -1;
782                 }
783         }
784
785         /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
786          * for the rest of the processes will be the same as DB_MODE_NONE */
787         if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
788                 dlg_db_mode = DB_MODE_NONE;
789         /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
790         if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
791                         rank==PROC_MAIN)
792                 dlg_db_mode = DB_MODE_NONE;
793
794         return 0;
795 }
796
797
798 static void mod_destroy(void)
799 {
800         if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
801                 dialog_update_db(0, 0);
802                 destroy_dlg_db();
803         }
804         dlg_bridge_destroy_hdrs();
805         /* no DB interaction from now on */
806         dlg_db_mode = DB_MODE_NONE;
807         destroy_dlg_table();
808         destroy_dlg_timer();
809         destroy_dlg_callbacks( DLGCB_CREATED|DLGCB_LOADED );
810         destroy_dlg_handlers();
811         destroy_dlg_profiles();
812 }
813
814
815 static int w_set_dlg_profile_helper(sip_msg_t *msg,
816                 struct dlg_profile_table *profile, str *value)
817 {
818         if (profile->has_value) {
819                 if (value==NULL || value->len<=0) {
820                         LM_ERR("invalid value parameter\n");
821                         return -1;
822                 }
823                 if ( set_dlg_profile( msg, value, profile) < 0 ) {
824                         LM_ERR("failed to set profile with key\n");
825                         return -1;
826                 }
827         } else {
828                 if ( set_dlg_profile( msg, NULL, profile) < 0 ) {
829                         LM_ERR("failed to set profile\n");
830                         return -1;
831                 }
832         }
833         return 1;
834 }
835
836 static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value)
837 {
838         pv_elem_t *pve = NULL;
839         str val_s = STR_NULL;
840
841         pve = (pv_elem_t *)value;
842         if(pve!=NULL) {
843                 if(pv_printf_s(msg, pve, &val_s)!=0 || val_s.len <= 0
844                                 || val_s.s == NULL) {
845                         LM_WARN("cannot get string for value\n");
846                         return -1;
847                 }
848         }
849
850         return w_set_dlg_profile_helper(msg, (struct dlg_profile_table*)profile,
851                                 &val_s);
852 }
853
854 static int w_unset_dlg_profile_helper(sip_msg_t *msg,
855                 struct dlg_profile_table *profile, str *value)
856 {
857         if (profile->has_value) {
858                 if (value==NULL || value->len<=0) {
859                         LM_ERR("invalid value parameter\n");
860                         return -1;
861                 }
862                 if ( unset_dlg_profile( msg, value, profile) < 0 ) {
863                         LM_ERR("failed to unset profile with key\n");
864                         return -1;
865                 }
866         } else {
867                 if ( unset_dlg_profile( msg, NULL, profile) < 0 ) {
868                         LM_ERR("failed to unset profile\n");
869                         return -1;
870                 }
871         }
872         return 1;
873 }
874
875 static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value)
876 {
877         pv_elem_t *pve = NULL;
878         str val_s = STR_NULL;
879
880         pve = (pv_elem_t *)value;
881         if(pve!=NULL) {
882                 if(pv_printf_s(msg, pve, &val_s)!=0 || val_s.len <= 0
883                                 || val_s.s == NULL) {
884                         LM_WARN("cannot get string for value\n");
885                         return -1;
886                 }
887         }
888
889         return w_unset_dlg_profile_helper(msg, (struct dlg_profile_table*)profile,
890                                 &val_s);
891 }
892
893 static int w_is_in_profile_helper(sip_msg_t *msg,
894                 struct dlg_profile_table *profile, str *value)
895 {
896         if (profile->has_value) {
897                 if (value==NULL || value->len<=0) {
898                         LM_ERR("invalid value parameter\n");
899                         return -1;
900                 }
901                 return is_dlg_in_profile( msg, profile, value);
902         } else {
903                 return is_dlg_in_profile( msg, profile, NULL);
904         }
905 }
906
907 static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value)
908 {
909         pv_elem_t *pve = NULL;
910         str val_s = STR_NULL;
911
912         pve = (pv_elem_t *)value;
913         if(pve!=NULL) {
914                 if(pv_printf_s(msg, pve, &val_s)!=0 || val_s.len <= 0
915                                 || val_s.s == NULL) {
916                         LM_WARN("cannot get string for value\n");
917                         return -1;
918                 }
919         }
920
921         return w_is_in_profile_helper(msg, (struct dlg_profile_table*)profile,
922                                 &val_s);
923 }
924
925 /**
926  * get dynamic name profile size
927  */
928 static int w_get_profile_size_helper(sip_msg_t *msg,
929                 struct dlg_profile_table *profile, str *value, pv_spec_t *spd)
930 {
931         unsigned int size;
932         pv_value_t val;
933
934         if (profile->has_value) {
935                 if(value==NULL || value->s==NULL || value->len<=0) {
936                         LM_ERR("invalid value parameter\n");
937                         return -1;
938                 }
939                 size = get_profile_size( profile, value );
940         } else {
941                 size = get_profile_size( profile, NULL );
942         }
943
944         memset(&val, 0, sizeof(pv_value_t));
945         val.flags = PV_VAL_INT|PV_TYPE_INT;
946         val.ri = (int)size;
947
948         if(spd->setf(msg, &spd->pvp, (int)EQ_T, &val)<0)
949         {
950                 LM_ERR("setting profile PV failed\n");
951                 return -1;
952         }
953
954         return 1;
955 }
956
957 static int w_get_profile_size3(struct sip_msg *msg, char *profile,
958                 char *value, char *result)
959 {
960         pv_elem_t *pve = NULL;
961         str val_s = STR_NULL;
962         pv_spec_t *spd = NULL;
963
964         if(result!=NULL)
965         {
966                 pve = (pv_elem_t *)value;
967                 spd = (pv_spec_t *)result;
968         } else {
969                 pve = NULL;
970                 spd = (pv_spec_t *)value;
971         }
972         if (pve!=NULL) {
973                 if ( pv_printf_s(msg, pve, &val_s)!=0
974                                 || val_s.len == 0 || val_s.s == NULL) {
975                         LM_WARN("cannot get string for value\n");
976                         return -1;
977                 }
978         }
979
980         return w_get_profile_size_helper(msg, (struct dlg_profile_table*)profile,
981                         (pve)?&val_s:NULL, spd);
982 }
983
984 /**
985  * get static name profile size
986  */
987 static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result)
988 {
989         return w_get_profile_size3(msg, profile, result, NULL);
990 }
991
992
993 static int ki_dlg_setflag(struct sip_msg *msg, int val)
994 {
995         dlg_ctx_t *dctx;
996         dlg_cell_t *d;
997
998         if(val<0 || val>31)
999                 return -1;
1000         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1001                 return -1;
1002
1003         dctx->flags |= 1<<val;
1004         d = dlg_get_by_iuid(&dctx->iuid);
1005         if(d!=NULL) {
1006                 d->sflags |= 1<<val;
1007                 dlg_release(d);
1008         }
1009         return 1;
1010 }
1011
1012 static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2)
1013 {
1014         int val;
1015
1016         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
1017         {
1018                 LM_ERR("no flag value\n");
1019                 return -1;
1020         }
1021
1022         return ki_dlg_setflag(msg, val);
1023 }
1024
1025 static int ki_dlg_resetflag(struct sip_msg *msg, int val)
1026 {
1027         dlg_ctx_t *dctx;
1028         dlg_cell_t *d;
1029
1030         if(val<0 || val>31)
1031                 return -1;
1032
1033         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1034                 return -1;
1035
1036         dctx->flags &= ~(1<<val);
1037         d = dlg_get_by_iuid(&dctx->iuid);
1038         if(d!=NULL) {
1039                 d->sflags &= ~(1<<val);
1040                 dlg_release(d);
1041         }
1042         return 1;
1043 }
1044
1045 static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2)
1046 {
1047         int val;
1048
1049         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
1050         {
1051                 LM_ERR("no flag value\n");
1052                 return -1;
1053         }
1054         return ki_dlg_resetflag(msg, val);
1055 }
1056
1057 static int ki_dlg_isflagset(struct sip_msg *msg, int val)
1058 {
1059         dlg_ctx_t *dctx;
1060         dlg_cell_t *d;
1061         int ret;
1062
1063         if(val<0 || val>31)
1064                 return -1;
1065
1066         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1067                 return -1;
1068
1069         d = dlg_get_by_iuid(&dctx->iuid);
1070         if(d!=NULL) {
1071                 ret = (d->sflags&(1<<val))?1:-1;
1072                 dlg_release(d);
1073                 return ret;
1074         }
1075         return (dctx->flags&(1<<val))?1:-1;
1076 }
1077
1078 static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2)
1079 {
1080         int val;
1081
1082         if(fixup_get_ivalue(msg, (gparam_p)flag, &val)!=0)
1083         {
1084                 LM_ERR("no flag value\n");
1085                 return -1;
1086         }
1087         return ki_dlg_isflagset(msg, val);
1088 }
1089
1090 /**
1091  *
1092  */
1093 static int w_dlg_manage(struct sip_msg *msg, char *s1, char *s2)
1094 {
1095         return dlg_manage(msg);
1096 }
1097
1098 static int w_dlg_bye(struct sip_msg *msg, char *side, char *s2)
1099 {
1100         dlg_cell_t *dlg = NULL;
1101         int n;
1102
1103         dlg = dlg_get_ctx_dialog();
1104         if(dlg==NULL)
1105                 return -1;
1106         
1107         n = (int)(long)side;
1108         if(n==1)
1109         {
1110                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
1111                         goto error;
1112                 goto done;
1113         } else if(n==2) {
1114                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
1115                         goto error;
1116                 goto done;
1117         } else {
1118                 if(dlg_bye_all(dlg, NULL)!=0)
1119                         goto error;
1120                 goto done;
1121         }
1122
1123 done:
1124         dlg_release(dlg);
1125         return 1;
1126
1127 error:
1128         dlg_release(dlg);
1129         return -1;
1130 }
1131
1132 static int w_dlg_refer(struct sip_msg *msg, char *side, char *to)
1133 {
1134         dlg_cell_t *dlg;
1135         int n;
1136         str st = {0,0};
1137
1138         dlg = dlg_get_ctx_dialog();
1139         if(dlg==NULL)
1140                 return -1;
1141         
1142         n = (int)(long)side;
1143
1144         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1145         {
1146                 LM_ERR("unable to get To\n");
1147                 goto error;
1148         }
1149         if(st.s==NULL || st.len == 0)
1150         {
1151                 LM_ERR("invalid To parameter\n");
1152                 goto error;
1153         }
1154         if(n==1)
1155         {
1156                 if(dlg_transfer(dlg, &st, DLG_CALLER_LEG)!=0)
1157                         goto error;
1158         } else {
1159                 if(dlg_transfer(dlg, &st, DLG_CALLEE_LEG)!=0)
1160                         goto error;
1161         }
1162
1163         dlg_release(dlg);
1164         return 1;
1165
1166 error:
1167         dlg_release(dlg);
1168         return -1;
1169 }
1170
1171 static int w_dlg_bridge(struct sip_msg *msg, char *from, char *to, char *op)
1172 {
1173         str sf = {0,0};
1174         str st = {0,0};
1175         str so = {0,0};
1176
1177         if(from==0 || to==0 || op==0)
1178         {
1179                 LM_ERR("invalid parameters\n");
1180                 return -1;
1181         }
1182
1183         if(fixup_get_svalue(msg, (gparam_p)from, &sf)!=0)
1184         {
1185                 LM_ERR("unable to get From\n");
1186                 return -1;
1187         }
1188         if(sf.s==NULL || sf.len == 0)
1189         {
1190                 LM_ERR("invalid From parameter\n");
1191                 return -1;
1192         }
1193         if(fixup_get_svalue(msg, (gparam_p)to, &st)!=0)
1194         {
1195                 LM_ERR("unable to get To\n");
1196                 return -1;
1197         }
1198         if(st.s==NULL || st.len == 0)
1199         {
1200                 LM_ERR("invalid To parameter\n");
1201                 return -1;
1202         }
1203         if(fixup_get_svalue(msg, (gparam_p)op, &so)!=0)
1204         {
1205                 LM_ERR("unable to get OP\n");
1206                 return -1;
1207         }
1208
1209         if(dlg_bridge(&sf, &st, &so, NULL)!=0)
1210                 return -1;
1211         return 1;
1212 }
1213
1214 static int ki_dlg_bridge(sip_msg_t *msg, str *sfrom, str *sto, str *soproxy)
1215 {
1216         if(dlg_bridge(sfrom, sto, soproxy, NULL)!=0)
1217                 return -1;
1218         return 1;
1219
1220 }
1221
1222 /**
1223  *
1224  */
1225 static int w_dlg_set_timeout(struct sip_msg *msg, char *pto, char *phe, char *phi)
1226 {
1227         int to = 0;
1228         unsigned int he = 0;
1229         unsigned int hi = 0;
1230         dlg_cell_t *dlg = NULL;
1231
1232         if(fixup_get_ivalue(msg, (gparam_p)pto, &to)!=0)
1233         {
1234                 LM_ERR("no timeout value\n");
1235                 return -1;
1236         }
1237         if(to<=0) {
1238                 LM_ERR("invalid timeout value: %d\n", to);
1239                 return -1;
1240         }
1241         if(phe!=NULL)
1242         {
1243                 if(phi==NULL) {
1244                         LM_ERR("invalid number of parameters\n");
1245                         return -1;
1246                 }
1247                 if(fixup_get_ivalue(msg, (gparam_p)phe, (int*)&he)!=0)
1248                 {
1249                         LM_ERR("no hash entry value value\n");
1250                         return -1;
1251                 }
1252                 if(fixup_get_ivalue(msg, (gparam_p)phi, (int*)&hi)!=0)
1253                 {
1254                         LM_ERR("no hash id value value\n");
1255                         return -1;
1256                 }
1257                 dlg = dlg_lookup(he, hi);
1258         } else {
1259                 dlg = dlg_get_msg_dialog(msg);
1260         }
1261
1262         if(dlg==NULL)
1263         {
1264                 LM_DBG("no dialog found\n");
1265                 return -1;
1266         }
1267
1268         if(update_dlg_timeout(dlg, to) != 0)
1269                 return -1;
1270
1271         return 1;
1272 }
1273
1274 /**
1275  *
1276  */
1277 static int ki_dlg_set_property(sip_msg_t *msg, str *pval)
1278 {
1279         dlg_ctx_t *dctx;
1280         dlg_cell_t *d;
1281
1282         if(pval->len<=0) {
1283                 LM_ERR("empty property value\n");
1284                 return -1;
1285         }
1286         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1287                 return -1;
1288
1289         if(pval->len==6 && strncmp(pval->s, "ka-src", 6)==0) {
1290                 dctx->iflags |= DLG_IFLAG_KA_SRC;
1291                 d = dlg_get_by_iuid(&dctx->iuid);
1292                 if(d!=NULL) {
1293                         d->iflags |= DLG_IFLAG_KA_SRC;
1294                         dlg_release(d);
1295                 }
1296         } else if(pval->len==6 && strncmp(pval->s, "ka-dst", 6)==0) {
1297                 dctx->iflags |= DLG_IFLAG_KA_DST;
1298                 d = dlg_get_by_iuid(&dctx->iuid);
1299                 if(d!=NULL) {
1300                         d->iflags |= DLG_IFLAG_KA_DST;
1301                         dlg_release(d);
1302                 }
1303         } else if(pval->len==15 && strncmp(pval->s, "timeout-noreset", 15)==0) {
1304                 dctx->iflags |= DLG_IFLAG_TIMER_NORESET;
1305                 d = dlg_get_by_iuid(&dctx->iuid);
1306                 if(d!=NULL) {
1307                         d->iflags |= DLG_IFLAG_TIMER_NORESET;
1308                         dlg_release(d);
1309                 }
1310         } else {
1311                 LM_ERR("unknown property value [%.*s]\n", pval->len, pval->s);
1312                 return -1;
1313         }
1314
1315         return 1;
1316 }
1317
1318 /**
1319  *
1320  */
1321 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2)
1322 {
1323         str val;
1324
1325         if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0)
1326         {
1327                 LM_ERR("no property value\n");
1328                 return -1;
1329         }
1330
1331         return ki_dlg_set_property(msg, &val);
1332 }
1333
1334 static int w_dlg_set_timeout_by_profile3(struct sip_msg *msg, char *profile,
1335                                         char *value, char *timeout_str) 
1336 {
1337         pv_elem_t *pve = NULL;
1338         str val_s;
1339
1340         pve = (pv_elem_t *) value;
1341
1342         if(pve != NULL && ((struct dlg_profile_table *) profile)->has_value) {
1343                 if(pv_printf_s(msg,pve, &val_s) != 0 || 
1344                    !val_s.s || val_s.len == 0) {
1345                         LM_WARN("cannot get string for value\n");
1346                         return -1;
1347                 }
1348         }
1349
1350         if(dlg_set_timeout_by_profile((struct dlg_profile_table *) profile,
1351                                    &val_s, atoi(timeout_str)) != 0)
1352                 return -1;
1353
1354         return 1;
1355 }
1356
1357 static int w_dlg_set_timeout_by_profile2(struct sip_msg *msg, 
1358                                          char *profile, char *timeout_str)
1359 {
1360         return w_dlg_set_timeout_by_profile3(msg, profile, NULL, timeout_str);
1361 }
1362
1363 void dlg_ka_timer_exec(unsigned int ticks, void* param)
1364 {
1365         dlg_ka_run(ticks);
1366 }
1367
1368 void dlg_clean_timer_exec(unsigned int ticks, void* param)
1369 {
1370         dlg_clean_run(ticks);
1371         remove_expired_remote_profiles(time(NULL));
1372 }
1373
1374 static int fixup_dlg_bye(void** param, int param_no)
1375 {
1376         char *val;
1377         int n = 0;
1378
1379         if (param_no==1) {
1380                 val = (char*)*param;
1381                 if (strcasecmp(val,"all")==0) {
1382                         n = 0;
1383                 } else if (strcasecmp(val,"caller")==0) {
1384                         n = 1;
1385                 } else if (strcasecmp(val,"callee")==0) {
1386                         n = 2;
1387                 } else {
1388                         LM_ERR("invalid param \"%s\"\n", val);
1389                         return E_CFG;
1390                 }
1391                 pkg_free(*param);
1392                 *param=(void*)(long)n;
1393         } else {
1394                 LM_ERR("called with parameter != 1\n");
1395                 return E_BUG;
1396         }
1397         return 0;
1398 }
1399
1400 static int fixup_dlg_refer(void** param, int param_no)
1401 {
1402         char *val;
1403         int n = 0;
1404
1405         if (param_no==1) {
1406                 val = (char*)*param;
1407                 if (strcasecmp(val,"caller")==0) {
1408                         n = 1;
1409                 } else if (strcasecmp(val,"callee")==0) {
1410                         n = 2;
1411                 } else {
1412                         LM_ERR("invalid param \"%s\"\n", val);
1413                         return E_CFG;
1414                 }
1415                 pkg_free(*param);
1416                 *param=(void*)(long)n;
1417         } else if (param_no==2) {
1418                 return fixup_spve_null(param, 1);
1419         } else {
1420                 LM_ERR("called with parameter idx %d\n", param_no);
1421                 return E_BUG;
1422         }
1423         return 0;
1424 }
1425
1426 static int fixup_dlg_bridge(void** param, int param_no)
1427 {
1428         if (param_no>=1 && param_no<=3) {
1429                 return fixup_spve_null(param, 1);
1430         } else {
1431                 LM_ERR("called with parameter idx %d\n", param_no);
1432                 return E_BUG;
1433         }
1434         return 0;
1435 }
1436
1437 static int ki_dlg_get(sip_msg_t *msg, str *sc, str *sf, str *st)
1438 {
1439         dlg_cell_t *dlg = NULL;
1440         unsigned int dir = 0;
1441
1442         if(sc==NULL || sc->s==NULL || sc->len == 0) {
1443                 LM_ERR("invalid Call-ID parameter\n");
1444                 return -1;
1445         }
1446         if(sf==NULL || sf->s==NULL || sf->len == 0) {
1447                 LM_ERR("invalid From tag parameter\n");
1448                 return -1;
1449         }
1450         if(st==NULL || st->s==NULL || st->len == 0) {
1451                 LM_ERR("invalid To tag parameter\n");
1452                 return -1;
1453         }
1454
1455         dlg = get_dlg(sc, sf, st, &dir);
1456         if(dlg==NULL)
1457                 return -1;
1458         /* set shorcut to dialog internal unique id */
1459         _dlg_ctx.iuid.h_entry = dlg->h_entry;
1460         _dlg_ctx.iuid.h_id = dlg->h_id;
1461         _dlg_ctx.dir = dir;
1462         dlg_release(dlg);
1463         return 1;
1464 }
1465
1466 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1467 {
1468         str sc = {0,0};
1469         str sf = {0,0};
1470         str st = {0,0};
1471
1472         if(ci==0 || ft==0 || tt==0)
1473         {
1474                 LM_ERR("invalid parameters\n");
1475                 return -1;
1476         }
1477
1478         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1479         {
1480                 LM_ERR("unable to get Call-ID\n");
1481                 return -1;
1482         }
1483
1484         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1485         {
1486                 LM_ERR("unable to get From tag\n");
1487                 return -1;
1488         }
1489
1490         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1491         {
1492                 LM_ERR("unable to get To Tag\n");
1493                 return -1;
1494         }
1495         if(st.s==NULL || st.len == 0)
1496         {
1497                 LM_ERR("invalid To tag parameter\n");
1498                 return -1;
1499         }
1500
1501         return ki_dlg_get(msg, &sc, &sf, &st);
1502 }
1503
1504 /**
1505  *
1506  */
1507 static int w_dlg_remote_profile(sip_msg_t *msg, char *cmd, char *pname,
1508                 char *pval, char *puid, char *expires)
1509 {
1510         str scmd;
1511         str sname;
1512         str sval;
1513         str suid;
1514         int ival;
1515         int ret;
1516
1517         if(fixup_get_svalue(msg, (gparam_t*)cmd, &scmd)!=0) {
1518                 LM_ERR("unable to get command\n");
1519                 return -1;
1520         }
1521         if(fixup_get_svalue(msg, (gparam_t*)pname, &sname)!=0) {
1522                 LM_ERR("unable to get profile name\n");
1523                 return -1;
1524         }
1525         if(fixup_get_svalue(msg, (gparam_t*)pval, &sval)!=0) {
1526                 LM_ERR("unable to get profile value\n");
1527                 return -1;
1528         }
1529         if(fixup_get_svalue(msg, (gparam_t*)puid, &suid)!=0) {
1530                 LM_ERR("unable to get profile uid\n");
1531                 return -1;
1532         }
1533         if(fixup_get_ivalue(msg, (gparam_t*)expires, &ival)!=0) {
1534                 LM_ERR("no hash entry value value\n");
1535                 return -1;
1536         }
1537
1538         ret = dlg_cmd_remote_profile(&scmd, &sname, &sval, &suid, (time_t)ival, 0);
1539         if(ret==0)
1540                 return 1;
1541         return ret;
1542 }
1543
1544 static int fixup_dlg_remote_profile(void** param, int param_no)
1545 {
1546         if(param_no>=1 && param_no<=4)
1547                 return fixup_spve_null(param, 1);
1548         if(param_no==5)
1549                 return fixup_igp_null(param, 1);
1550         return 0;
1551 }
1552
1553 /**
1554  *
1555  */
1556 static int ki_dlg_bye(sip_msg_t *msg, str *side)
1557 {
1558         dlg_cell_t *dlg = NULL;
1559
1560         dlg = dlg_get_ctx_dialog();
1561         if(dlg==NULL)
1562                 return -1;
1563
1564         if(side->len==6 && strncasecmp(side->s, "caller", 6)==0)
1565         {
1566                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
1567                         goto error;
1568                 goto done;
1569         } else if(side->len==6 && strncasecmp(side->s, "callee", 6)==0) {
1570                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
1571                         goto error;
1572                 goto done;
1573         } else {
1574                 if(dlg_bye_all(dlg, NULL)!=0)
1575                         goto error;
1576                 goto done;
1577         }
1578
1579 done:
1580         dlg_release(dlg);
1581         return 1;
1582
1583 error:
1584         dlg_release(dlg);
1585         return -1;
1586 }
1587
1588 /**
1589  *
1590  */
1591 static int ki_dlg_set_timeout_id(sip_msg_t *msg, int to, int he, int hi)
1592 {
1593         dlg_cell_t *dlg = NULL;
1594
1595         dlg = dlg_lookup(he, hi);
1596         if(dlg==NULL) {
1597                 LM_DBG("no dialog found\n");
1598                 return -1;
1599         }
1600
1601         /* update_dlg_timeout() does dlg_release() */
1602         if(update_dlg_timeout(dlg, to) != 0)
1603                 return -1;
1604
1605         return 1;
1606 }
1607
1608 /**
1609  *
1610  */
1611 static int ki_dlg_set_timeout(sip_msg_t *msg, int to)
1612 {
1613         dlg_cell_t *dlg = NULL;
1614
1615         dlg = dlg_get_msg_dialog(msg);
1616         if(dlg==NULL) {
1617                 LM_DBG("no dialog found\n");
1618                 return -1;
1619         }
1620
1621         /* update_dlg_timeout() does dlg_release() */
1622         if(update_dlg_timeout(dlg, to) != 0)
1623                 return -1;
1624
1625         return 1;
1626
1627 }
1628
1629 /**
1630  *
1631  */
1632 static int ki_set_dlg_profile_static(sip_msg_t *msg, str *sprofile)
1633 {
1634         struct dlg_profile_table *profile = NULL;
1635
1636         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1637                 LM_ERR("invalid profile identifier\n");
1638                 return -1;
1639         }
1640         profile = search_dlg_profile( sprofile );
1641         if (profile==NULL) {
1642                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1643                 return -1;
1644         }
1645
1646         return w_set_dlg_profile_helper(msg, profile, NULL);
1647 }
1648
1649 /**
1650  *
1651  */
1652 static int ki_set_dlg_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1653 {
1654         struct dlg_profile_table *profile = NULL;
1655
1656         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1657                 LM_ERR("invalid profile identifier\n");
1658                 return -1;
1659         }
1660         profile = search_dlg_profile( sprofile );
1661         if (profile==NULL) {
1662                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1663                 return -1;
1664         }
1665
1666         return w_set_dlg_profile_helper(msg, profile, svalue);
1667 }
1668
1669 /**
1670  *
1671  */
1672 static int ki_unset_dlg_profile_static(sip_msg_t *msg, str *sprofile)
1673 {
1674         struct dlg_profile_table *profile = NULL;
1675
1676         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1677                 LM_ERR("invalid profile identifier\n");
1678                 return -1;
1679         }
1680         profile = search_dlg_profile( sprofile );
1681         if (profile==NULL) {
1682                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1683                 return -1;
1684         }
1685
1686         return w_unset_dlg_profile_helper(msg, profile, NULL);
1687 }
1688
1689 /**
1690  *
1691  */
1692 static int ki_unset_dlg_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1693 {
1694         struct dlg_profile_table *profile = NULL;
1695
1696         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1697                 LM_ERR("invalid profile identifier\n");
1698                 return -1;
1699         }
1700         profile = search_dlg_profile( sprofile );
1701         if (profile==NULL) {
1702                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1703                 return -1;
1704         }
1705
1706         return w_unset_dlg_profile_helper(msg, profile, svalue);
1707 }
1708
1709 /**
1710  *
1711  */
1712 static int ki_is_in_profile_static(sip_msg_t *msg, str *sprofile)
1713 {
1714         struct dlg_profile_table *profile = NULL;
1715
1716         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1717                 LM_ERR("invalid profile identifier\n");
1718                 return -1;
1719         }
1720         profile = search_dlg_profile( sprofile );
1721         if (profile==NULL) {
1722                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1723                 return -1;
1724         }
1725
1726         return w_is_in_profile_helper(msg, profile, NULL);
1727 }
1728
1729 /**
1730  *
1731  */
1732 static int ki_is_in_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1733 {
1734         struct dlg_profile_table *profile = NULL;
1735
1736         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1737                 LM_ERR("invalid profile identifier\n");
1738                 return -1;
1739         }
1740         profile = search_dlg_profile( sprofile );
1741         if (profile==NULL) {
1742                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1743                 return -1;
1744         }
1745
1746         return w_is_in_profile_helper(msg, profile, svalue);
1747 }
1748
1749 /**
1750  *
1751  */
1752 static int ki_get_profile_size_static(sip_msg_t *msg, str *sprofile, str *spv)
1753 {
1754         struct dlg_profile_table *profile = NULL;
1755         pv_spec_t *pvs = NULL;
1756
1757         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1758                 LM_ERR("invalid profile identifier\n");
1759                 return -1;
1760         }
1761         if(spv==NULL || spv->s==NULL || spv->len<=0) {
1762                 LM_ERR("invalid destination var name\n");
1763                 return -1;
1764         }
1765         profile = search_dlg_profile( sprofile );
1766         if (profile==NULL) {
1767                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1768                 return -1;
1769         }
1770         pvs = pv_cache_get(spv);
1771         if(pvs==NULL) {
1772                 LM_ERR("cannot get pv spec for [%.*s]\n", spv->len, spv->s);
1773                 return -1;
1774         }
1775         if (pvs->type!=PVT_AVP && pvs->type!=PVT_SCRIPTVAR) {
1776                 LM_ERR("return must be an AVP or SCRIPT VAR!\n");
1777                 return -1;
1778         }
1779
1780         return w_get_profile_size_helper(msg, profile, NULL, pvs);
1781 }
1782
1783 /**
1784  *
1785  */
1786 static int ki_get_profile_size(sip_msg_t *msg, str *sprofile, str *svalue,
1787                 str *spv)
1788 {
1789         struct dlg_profile_table *profile = NULL;
1790         pv_spec_t *pvs = NULL;
1791
1792         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1793                 LM_ERR("invalid profile identifier\n");
1794                 return -1;
1795         }
1796         if(spv==NULL || spv->s==NULL || spv->len<=0) {
1797                 LM_ERR("invalid destination var name\n");
1798                 return -1;
1799         }
1800         profile = search_dlg_profile( sprofile );
1801         if (profile==NULL) {
1802                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1803                 return -1;
1804         }
1805         pvs = pv_cache_get(spv);
1806         if(pvs==NULL) {
1807                 LM_ERR("cannot get pv spec for [%.*s]\n", spv->len, spv->s);
1808                 return -1;
1809         }
1810         if (pvs->type!=PVT_AVP && pvs->type!=PVT_SCRIPTVAR) {
1811                 LM_ERR("return must be an AVP or SCRIPT VAR!\n");
1812                 return -1;
1813         }
1814
1815         return w_get_profile_size_helper(msg, profile, svalue, pvs);
1816 }
1817
1818 /**
1819  *
1820  */
1821 static int ki_dlg_db_load_callid(sip_msg_t *msg, str *callid)
1822 {
1823         int ret;
1824
1825         ret = load_dialog_info_from_db(dlg_hash_size, db_fetch_rows, 1, callid);
1826
1827         if(ret==0) return 1;
1828         return ret;
1829 }
1830
1831 /**
1832  *
1833  */
1834 static int w_dlg_db_load_callid(sip_msg_t *msg, char *ci, char *p2)
1835 {
1836         str sc = {0,0};
1837
1838         if(ci==0) {
1839                 LM_ERR("invalid parameters\n");
1840                 return -1;
1841         }
1842
1843         if(fixup_get_svalue(msg, (gparam_t*)ci, &sc)!=0) {
1844                 LM_ERR("unable to get Call-ID\n");
1845                 return -1;
1846         }
1847
1848         return ki_dlg_db_load_callid(msg, &sc);
1849 }
1850
1851 /**
1852  *
1853  */
1854 static int ki_dlg_db_load_extra(sip_msg_t *msg)
1855 {
1856         int ret;
1857
1858         ret = load_dialog_info_from_db(dlg_hash_size, db_fetch_rows, 2, NULL);
1859
1860         if(ret==0) return 1;
1861         return ret;
1862 }
1863
1864 /**
1865  *
1866  */
1867 static int w_dlg_db_load_extra(sip_msg_t *msg, char *p1, char *p2)
1868 {
1869         return ki_dlg_db_load_extra(msg);
1870 }
1871
1872 /**
1873  *
1874  */
1875 static int ki_dlg_var_sets(sip_msg_t *msg, str *name, str *val)
1876 {
1877         dlg_cell_t *dlg;
1878         int ret;
1879
1880         dlg = dlg_get_msg_dialog(msg);
1881         ret = set_dlg_variable_unsafe(dlg, name, val);
1882         if(dlg) {
1883                 dlg_release(dlg);
1884         }
1885
1886         return (ret==0)?1:ret;
1887 }
1888
1889 /**
1890  *
1891  */
1892 static sr_kemi_xval_t _sr_kemi_dialog_xval = {0};
1893
1894 /**
1895  *
1896  */
1897 static sr_kemi_xval_t* ki_dlg_var_get_mode(sip_msg_t *msg, str *name, int rmode)
1898 {
1899         dlg_cell_t *dlg;
1900         str *pval;
1901
1902         memset(&_sr_kemi_dialog_xval, 0, sizeof(sr_kemi_xval_t));
1903
1904         dlg = dlg_get_msg_dialog(msg);
1905         if(dlg==NULL) {
1906                 sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
1907                 return &_sr_kemi_dialog_xval;
1908         }
1909         pval = get_dlg_variable(dlg, name);
1910         if(pval==NULL || pval->s==NULL) {
1911                 sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
1912                 goto done;
1913         }
1914
1915         _sr_kemi_dialog_xval.vtype = SR_KEMIP_STR;
1916         _sr_kemi_dialog_xval.v.s = *pval;
1917
1918 done:
1919         dlg_release(dlg);
1920         return &_sr_kemi_dialog_xval;
1921 }
1922
1923 /**
1924  *
1925  */
1926 static sr_kemi_xval_t* ki_dlg_var_get(sip_msg_t *msg, str *name)
1927 {
1928         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_NONE);
1929 }
1930
1931 /**
1932  *
1933  */
1934 static sr_kemi_xval_t* ki_dlg_var_gete(sip_msg_t *msg, str *name)
1935 {
1936         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_EMPTY);
1937 }
1938 /**
1939  *
1940  */
1941 static sr_kemi_xval_t* ki_dlg_var_getw(sip_msg_t *msg, str *name)
1942 {
1943         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_PRINT);
1944 }
1945
1946 /**
1947  *
1948  */
1949 static int ki_dlg_var_rm(sip_msg_t *msg, str *name)
1950 {
1951         dlg_cell_t *dlg;
1952
1953         dlg = dlg_get_msg_dialog(msg);
1954         set_dlg_variable_unsafe(dlg, name, NULL);
1955         return 1;
1956 }
1957
1958 /**
1959  *
1960  */
1961 static int ki_dlg_var_is_null(sip_msg_t *msg, str *name)
1962 {
1963         dlg_cell_t *dlg;
1964         str *pval;
1965
1966         dlg = dlg_get_msg_dialog(msg);
1967         if(dlg==NULL) {
1968                 return 1;
1969         }
1970         pval = get_dlg_variable(dlg, name);
1971         if(pval==NULL || pval->s==NULL) {
1972                 return 1;
1973         }
1974         return -1;
1975 }
1976
1977 /**
1978  *
1979  */
1980 /* clang-format off */
1981 static sr_kemi_t sr_kemi_dialog_exports[] = {
1982         { str_init("dialog"), str_init("dlg_manage"),
1983                 SR_KEMIP_INT, dlg_manage,
1984                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1985                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1986         },
1987         { str_init("dialog"), str_init("dlg_bye"),
1988                 SR_KEMIP_INT, ki_dlg_bye,
1989                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1990                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1991         },
1992         { str_init("dialog"), str_init("is_known_dlg"),
1993                 SR_KEMIP_INT, is_known_dlg,
1994                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1995                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1996         },
1997         { str_init("dialog"), str_init("dlg_set_timeout"),
1998                 SR_KEMIP_INT, ki_dlg_set_timeout,
1999                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2000                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2001         },
2002         { str_init("dialog"), str_init("dlg_set_timeout_id"),
2003                 SR_KEMIP_INT, ki_dlg_set_timeout_id,
2004                 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_INT,
2005                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2006         },
2007         { str_init("dialog"), str_init("dlg_set_property"),
2008                 SR_KEMIP_INT, ki_dlg_set_property,
2009                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2010                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2011         },
2012         { str_init("dialog"), str_init("dlg_get"),
2013                 SR_KEMIP_INT, ki_dlg_get,
2014                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2015                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2016         },
2017         { str_init("dialog"), str_init("set_dlg_profile_static"),
2018                 SR_KEMIP_INT, ki_set_dlg_profile_static,
2019                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2020                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2021         },
2022         { str_init("dialog"), str_init("set_dlg_profile"),
2023                 SR_KEMIP_INT, ki_set_dlg_profile,
2024                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2025                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2026         },
2027         { str_init("dialog"), str_init("unset_dlg_profile_static"),
2028                 SR_KEMIP_INT, ki_unset_dlg_profile_static,
2029                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2030                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2031         },
2032         { str_init("dialog"), str_init("unset_dlg_profile"),
2033                 SR_KEMIP_INT, ki_unset_dlg_profile,
2034                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2035                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2036         },
2037         { str_init("dialog"), str_init("is_in_profile_static"),
2038                 SR_KEMIP_INT, ki_is_in_profile_static,
2039                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2040                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2041         },
2042         { str_init("dialog"), str_init("is_in_profile"),
2043                 SR_KEMIP_INT, ki_is_in_profile,
2044                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2045                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2046         },
2047         { str_init("dialog"), str_init("get_profile_size_static"),
2048                 SR_KEMIP_INT, ki_get_profile_size_static,
2049                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2050                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2051         },
2052         { str_init("dialog"), str_init("get_profile_size"),
2053                 SR_KEMIP_INT, ki_get_profile_size,
2054                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2055                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2056         },
2057         { str_init("dialog"), str_init("dlg_setflag"),
2058                 SR_KEMIP_INT, ki_dlg_setflag,
2059                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2060                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2061         },
2062         { str_init("dialog"), str_init("dlg_resetflag"),
2063                 SR_KEMIP_INT, ki_dlg_resetflag,
2064                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2065                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2066         },
2067         { str_init("dialog"), str_init("dlg_isflagset"),
2068                 SR_KEMIP_INT, ki_dlg_isflagset,
2069                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2070                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2071         },
2072         { str_init("dialog"), str_init("dlg_db_load_callid"),
2073                 SR_KEMIP_INT, ki_dlg_db_load_callid,
2074                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2075                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2076         },
2077         { str_init("dialog"), str_init("dlg_db_load_extra"),
2078                 SR_KEMIP_INT, ki_dlg_db_load_extra,
2079                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
2080                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2081         },
2082         { str_init("dialog"), str_init("var_sets"),
2083                 SR_KEMIP_INT, ki_dlg_var_sets,
2084                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2085                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2086         },
2087         { str_init("dialog"), str_init("var_get"),
2088                 SR_KEMIP_XVAL, ki_dlg_var_get,
2089                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2090                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2091         },
2092         { str_init("dialog"), str_init("var_gete"),
2093                 SR_KEMIP_XVAL, ki_dlg_var_gete,
2094                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2095                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2096         },
2097         { str_init("dialog"), str_init("var_getw"),
2098                 SR_KEMIP_XVAL, ki_dlg_var_getw,
2099                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2100                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2101         },
2102         { str_init("dialog"), str_init("var_rm"),
2103                 SR_KEMIP_INT, ki_dlg_var_rm,
2104                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2105                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2106         },
2107         { str_init("dialog"), str_init("var_is_null"),
2108                 SR_KEMIP_INT, ki_dlg_var_is_null,
2109                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2110                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2111         },
2112         { str_init("dialog"), str_init("dlg_bridge"),
2113                 SR_KEMIP_INT, ki_dlg_bridge,
2114                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2115                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2116         },
2117
2118         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
2119 };
2120 /* clang-format on */
2121
2122 /**
2123  *
2124  */
2125 int mod_register(char *path, int *dlflags, void *p1, void *p2)
2126 {
2127         sr_kemi_modules_add(sr_kemi_dialog_exports);
2128         return 0;
2129 }
2130
2131 /**************************** RPC functions ******************************/
2132 /*!
2133  * \brief Helper method that outputs a dialog via the RPC interface
2134  * \see rpc_print_dlg
2135  * \param rpc RPC node that should be filled
2136  * \param c RPC void pointer
2137  * \param dlg printed dialog
2138  * \param with_context if 1 then the dialog context will be also printed
2139  * \return 0 on success, -1 on failure
2140  */
2141 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, dlg_cell_t *dlg,
2142                 int with_context)
2143 {
2144         rpc_cb_ctx_t rpc_cb;
2145         void *h, *sh, *ssh;
2146         dlg_profile_link_t *pl;
2147         dlg_var_t *var;
2148
2149         if (rpc->add(c, "{", &h) < 0) goto error;
2150
2151         rpc->struct_add(h, "dddSSSddddddddd",
2152                 "h_entry", dlg->h_entry,
2153                 "h_id", dlg->h_id,
2154                 "ref", dlg->ref,
2155                 "call-id", &dlg->callid,
2156                 "from_uri", &dlg->from_uri,
2157                 "to_uri", &dlg->to_uri,
2158                 "state", dlg->state,
2159                 "start_ts", dlg->start_ts,
2160                 "init_ts", dlg->init_ts,
2161                 "end_ts", dlg->end_ts,
2162                 "timeout", dlg->tl.timeout ? time(0) + dlg->tl.timeout - get_ticks() : 0,
2163                 "lifetime", dlg->lifetime,
2164                 "dflags", dlg->dflags,
2165                 "sflags", dlg->sflags,
2166                 "iflags", dlg->iflags);
2167
2168         if (rpc->struct_add(h, "{", "caller", &sh) < 0) goto error;
2169         rpc->struct_add(sh, "SSSSS",
2170                 "tag", &dlg->tag[DLG_CALLER_LEG],
2171                 "contact", &dlg->contact[DLG_CALLER_LEG],
2172                 "cseq", &dlg->cseq[DLG_CALLER_LEG],
2173                 "route_set", &dlg->route_set[DLG_CALLER_LEG],
2174                 "socket", dlg->bind_addr[DLG_CALLER_LEG] ? &dlg->bind_addr[DLG_CALLER_LEG]->sock_str : &empty_str);
2175
2176         if (rpc->struct_add(h, "{", "callee", &sh) < 0) goto error;
2177         rpc->struct_add(sh, "SSSSS",
2178                 "tag", &dlg->tag[DLG_CALLEE_LEG],
2179                 "contact", &dlg->contact[DLG_CALLEE_LEG],
2180                 "cseq", &dlg->cseq[DLG_CALLEE_LEG],
2181                 "route_set", &dlg->route_set[DLG_CALLEE_LEG],
2182                 "socket", dlg->bind_addr[DLG_CALLEE_LEG] ? &dlg->bind_addr[DLG_CALLEE_LEG]->sock_str : &empty_str);
2183
2184         if (rpc->struct_add(h, "[", "profiles", &sh) < 0) goto error;
2185         for (pl = dlg->profile_links ; pl && (dlg->state<DLG_STATE_DELETED) ; pl=pl->next) {
2186                 if (pl->profile->has_value) {
2187                         rpc->array_add(sh, "{", &ssh);
2188                         rpc->struct_add(ssh, "S", pl->profile->name.s, &pl->hash_linker.value);
2189                 } else {
2190                         rpc->array_add(sh, "S", &pl->profile->name);
2191                 }
2192         }
2193
2194         if (rpc->struct_add(h, "[", "variables", &sh) < 0) goto error;
2195         for(var=dlg->vars ; var && (dlg->state<DLG_STATE_DELETED) ; var=var->next) {
2196                 rpc->array_add(sh, "{", &ssh);
2197                 rpc->struct_add(ssh, "S", var->key.s, &var->value);
2198         }
2199
2200         if (with_context) {
2201                 rpc_cb.rpc = rpc;
2202                 rpc_cb.c = h;
2203                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
2204         }
2205
2206         return;
2207 error:
2208         LM_ERR("Failed to add item to RPC response\n");
2209         return;
2210 }
2211
2212 /*!
2213  * \brief Helper function that outputs all dialogs via the RPC interface
2214  * \see rpc_print_dlgs
2215  * \param rpc RPC node that should be filled
2216  * \param c RPC void pointer
2217  * \param with_context if 1 then the dialog context will be also printed
2218  */
2219 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
2220 {
2221         dlg_cell_t *dlg;
2222         unsigned int i;
2223
2224         for( i=0 ; i<d_table->size ; i++ ) {
2225                 dlg_lock( d_table, &(d_table->entries[i]) );
2226
2227                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
2228                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
2229                 }
2230                 dlg_unlock( d_table, &(d_table->entries[i]) );
2231         }
2232 }
2233
2234 /*!
2235  * \brief Helper function that outputs a dialog via the RPC interface
2236  * \see rpc_print_dlgs
2237  * \param rpc RPC node that should be filled
2238  * \param c RPC void pointer
2239  * \param with_context if 1 then the dialog context will be also printed
2240  */
2241 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
2242         str callid, ft;
2243         str *from_tag = NULL;
2244         dlg_entry_t *d_entry;
2245         dlg_cell_t *dlg;
2246         unsigned int h_entry;
2247
2248         if (rpc->scan(c, ".S", &callid) < 1) return;
2249
2250         h_entry = core_hash( &callid, 0, d_table->size);
2251         d_entry = &(d_table->entries[h_entry]);
2252
2253         if (rpc->scan(c, "*.S", &ft) == 1) {
2254                 from_tag = &ft;
2255         }
2256
2257         dlg_lock( d_table, d_entry);
2258         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
2259                 if (match_downstream_dialog( dlg, &callid, from_tag)==1) {
2260                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
2261                 }
2262         }
2263         dlg_unlock( d_table, d_entry);
2264 }
2265
2266 /*!
2267  * \brief Helper function that outputs the size of a given profile via the RPC interface
2268  * \see rpc_profile_get_size
2269  * \see rpc_profile_w_value_get_size
2270  * \param rpc RPC node that should be filled
2271  * \param c RPC void pointer
2272  * \param profile_name the given profile
2273  * \param value the given profile value
2274  */
2275 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name,
2276                 str *value) {
2277         unsigned int size;
2278         dlg_profile_table_t *profile;
2279
2280         profile = search_dlg_profile( profile_name );
2281         if (!profile) {
2282                 rpc->fault(c, 404, "Profile not found: %.*s",
2283                         profile_name->len, profile_name->s);
2284                 return;
2285         }
2286         size = get_profile_size(profile, value);
2287         rpc->add(c, "d", size);
2288         return;
2289 }
2290
2291 /*!
2292  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
2293  * \see rpc_profile_print_dlgs
2294  * \see rpc_profile_w_value_print_dlgs
2295  * \param rpc RPC node that should be filled
2296  * \param c RPC void pointer
2297  * \param profile_name the given profile
2298  * \param value the given profile value
2299  * \param with_context if 1 then the dialog context will be also printed
2300  */
2301 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name,
2302                 str *value) {
2303         dlg_profile_table_t *profile;
2304         dlg_profile_hash_t *ph;
2305         unsigned int i;
2306
2307         profile = search_dlg_profile( profile_name );
2308         if (!profile) {
2309                 rpc->fault(c, 404, "Profile not found: %.*s",
2310                         profile_name->len, profile_name->s);
2311                 return;
2312         }
2313
2314         /* go through the hash and print the dialogs */
2315         if (profile->has_value==0)
2316                 value=NULL;
2317
2318         lock_get( &profile->lock );
2319         for ( i=0 ; i< profile->size ; i++ ) {
2320                 ph = profile->entries[i].first;
2321                 if(ph) {
2322                         do {
2323                                 if ((!value || (STR_EQ(*value, ph->value))) && ph->dlg) {
2324                                         /* print dialog */
2325                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
2326                                 }
2327                                 /* next */
2328                                 ph=ph->next;
2329                         }while(ph!=profile->entries[i].first);
2330                 }
2331         }
2332         lock_release(&profile->lock);
2333 }
2334
2335 /*
2336  * Wrapper around is_known_dlg().
2337  */
2338
2339 static int w_is_known_dlg(sip_msg_t *msg) {
2340         return  is_known_dlg(msg);
2341 }
2342
2343 static int w_dlg_set_ruri(sip_msg_t *msg, char *p1, char *p2)
2344 {
2345         return  dlg_set_ruri(msg);
2346 }
2347
2348 static const char *rpc_print_dlgs_doc[2] = {
2349         "Print all dialogs", 0
2350 };
2351 static const char *rpc_print_dlgs_ctx_doc[2] = {
2352         "Print all dialogs with associated context", 0
2353 };
2354 static const char *rpc_dlg_list_match_doc[2] = {
2355         "Print matching dialogs", 0
2356 };
2357 static const char *rpc_dlg_list_match_ctx_doc[2] = {
2358         "Print matching dialogs with associated context", 0
2359 };
2360 static const char *rpc_print_dlg_doc[2] = {
2361         "Print dialog based on callid and optionally fromtag", 0
2362 };
2363 static const char *rpc_print_dlg_ctx_doc[2] = {
2364         "Print dialog with associated context based on callid and optionally fromtag", 0
2365 };
2366 static const char *rpc_end_dlg_entry_id_doc[2] = {
2367         "End a given dialog based on [h_entry] [h_id]", 0
2368 };
2369 static const char *rpc_dlg_terminate_dlg_doc[2] = {
2370         "End a given dialog based on callid", 0
2371 };
2372 static const char *rpc_profile_get_size_doc[2] = {
2373         "Returns the number of dialogs belonging to a profile", 0
2374 };
2375 static const char *rpc_profile_print_dlgs_doc[2] = {
2376         "Lists all the dialogs belonging to a profile", 0
2377 };
2378 static const char *rpc_dlg_bridge_doc[2] = {
2379         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:"
2380                 " to, from, [outbound SIP proxy]", 0
2381 };
2382 static const char *rpc_dlg_is_alive_doc[2] = {
2383         "Check whether dialog is alive or not", 0
2384 };
2385
2386
2387 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
2388         internal_rpc_print_dlgs(rpc, c, 0);
2389 }
2390 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
2391         internal_rpc_print_dlgs(rpc, c, 1);
2392 }
2393 static void rpc_print_dlg(rpc_t *rpc, void *c) {
2394         internal_rpc_print_single_dlg(rpc, c, 0);
2395 }
2396 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
2397         internal_rpc_print_single_dlg(rpc, c, 1);
2398 }
2399
2400 static void rpc_dlg_terminate_dlg(rpc_t *rpc,void *c){
2401         str callid = {NULL,0};
2402         str ftag = {NULL,0};
2403         str ttag = {NULL,0};
2404
2405         dlg_cell_t * dlg = NULL;
2406         unsigned int dir;
2407         int ret=0;
2408         dir = 0;
2409
2410
2411         if(rpc->scan(c, ".S.S.S", &callid,&ftag,&ttag)<3) {
2412                 LM_ERR("Unable to read the parameters dlg_terminate_dlg \n" );
2413                 rpc->fault(c, 400, "Need a Callid ,from tag ,to tag");
2414                 return;
2415         }
2416
2417         dlg=get_dlg(&callid, &ftag, &ttag, &dir);
2418
2419         if(dlg==NULL) {
2420                 LM_ERR("Couldnt find callid in dialog '%.*s' \n",callid.len, callid.s);
2421                 rpc->fault(c, 500, "Couldnt find callid in dialog");
2422                 return;
2423         }
2424
2425         LM_DBG("Dialog is found with callid  for terminate rpc '%.*s' \n",
2426                         callid.len, callid.s);
2427
2428         ret=dlg_bye_all(dlg, NULL);
2429
2430         LM_DBG("Dialog bye return code %d \n",ret);
2431
2432         if(ret>=0) {
2433         LM_WARN("Dialog is terminated callid: '%.*s' \n",
2434                         callid.len, callid.s);
2435         dlg_release(dlg);
2436     }
2437 }
2438
2439 static void rpc_dlg_is_alive(rpc_t *rpc, void *c)
2440 {
2441         str callid = {NULL, 0};
2442         str ftag = {NULL, 0};
2443         str ttag = {NULL, 0};
2444
2445         dlg_cell_t *dlg = NULL;
2446         unsigned int dir = 0;
2447         unsigned int state = 0;
2448
2449         if (rpc->scan(c, ".S.S.S", &callid, &ftag, &ttag) < 3) {
2450                 LM_DBG("Unable to read expected parameters\n");
2451                 rpc->fault(c, 400, "Too few parameters (required callid, from-tag, to-tag)");
2452                 return;
2453         }
2454
2455         dlg = get_dlg(&callid, &ftag, &ttag, &dir);
2456
2457         if (dlg == NULL) {
2458                 LM_DBG("Couldnt find dialog with callid: '%.*s'\n", callid.len, callid.s);
2459                 rpc->fault(c, 404, "Dialog not found");
2460                 return;
2461         }
2462         state = dlg->state;
2463     dlg_release(dlg);
2464         if (state != DLG_STATE_CONFIRMED) {
2465                 LM_DBG("Dialog with Call-ID '%.*s' is in state: %d (confirmed: %d)\n",
2466                                 callid.len, callid.s, state, DLG_STATE_CONFIRMED);
2467                 rpc->fault(c, 500, "Dialog not in confirmed state");
2468                 return;
2469         } else {
2470                 rpc->add(c, "s", "Alive");
2471         }
2472 }
2473
2474 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
2475         unsigned int h_entry, h_id;
2476         dlg_cell_t * dlg = NULL;
2477         str rpc_extra_hdrs = {NULL,0};
2478         int n;
2479
2480         n = rpc->scan(c, "dd", &h_entry, &h_id);
2481         if (n < 2) {
2482                 LM_ERR("unable to read the parameters (%d)\n", n);
2483                 rpc->fault(c, 500, "Invalid parameters");
2484                 return;
2485         }
2486         if(rpc->scan(c, "*S", &rpc_extra_hdrs)<1)
2487         {
2488                 rpc_extra_hdrs.s = NULL;
2489                 rpc_extra_hdrs.len = 0;
2490         }
2491
2492         dlg = dlg_lookup(h_entry, h_id);
2493         if(dlg==NULL) {
2494                 rpc->fault(c, 404, "Dialog not found");
2495                 return;
2496         }
2497
2498         dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
2499         dlg_release(dlg);
2500 }
2501 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
2502         str profile_name = {NULL,0};
2503         str value = {NULL,0};
2504
2505         if (rpc->scan(c, ".S", &profile_name) < 1) return;
2506         if (rpc->scan(c, "*.S", &value) > 0) {
2507                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
2508         } else {
2509                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
2510         }
2511         return;
2512 }
2513 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
2514         str profile_name = {NULL,0};
2515         str value = {NULL,0};
2516
2517         if (rpc->scan(c, ".S", &profile_name) < 1) return;
2518         if (rpc->scan(c, "*.S", &value) > 0) {
2519                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
2520         } else {
2521                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
2522         }
2523         return;
2524 }
2525
2526 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
2527         str from = {NULL,0};
2528         str to = {NULL,0};
2529         str op = {NULL,0};
2530         str bd = {NULL,0};
2531         int n;
2532
2533         n = rpc->scan(c, "SS", &from, &to);
2534         if (n< 2) {
2535                 LM_ERR("unable to read the parameters (%d)\n", n);
2536                 rpc->fault(c, 500, "Invalid parameters");
2537                 return;
2538         }
2539         if(rpc->scan(c, "*S", &op)<1) {
2540                 op.s = NULL;
2541                 op.len = 0;
2542         } else {
2543                 if(op.len==1 && *op.s=='.') {
2544                         op.s = NULL;
2545                         op.len = 0;
2546                 }
2547                 if(rpc->scan(c, "*S", &bd)<1) {
2548                         bd.s = NULL;
2549                         bd.len = 0;
2550                 } else {
2551                         if(bd.len==1 && *bd.s=='.') {
2552                                 bd.s = NULL;
2553                                 bd.len = 0;
2554                         } else if(bd.len==1 && *bd.s=='_') {
2555                                 bd.s = "";
2556                                 bd.len = 0;
2557                         }
2558                 }
2559         }
2560
2561         dlg_bridge(&from, &to, &op, &bd);
2562 }
2563
2564 static const char *rpc_dlg_stats_active_doc[2] = {
2565         "Get stats about active dialogs", 0
2566 };
2567
2568 /*!
2569  * \brief Print stats of active dialogs
2570  */
2571 static void rpc_dlg_stats_active(rpc_t *rpc, void *c)
2572 {
2573         dlg_cell_t *dlg;
2574         unsigned int i;
2575         int dlg_starting = 0;
2576         int dlg_connecting = 0;
2577         int dlg_answering = 0;
2578         int dlg_ongoing = 0;
2579         void *h;
2580
2581         for( i=0 ; i<d_table->size ; i++ ) {
2582                 dlg_lock( d_table, &(d_table->entries[i]) );
2583
2584                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
2585                         switch(dlg->state) {
2586                                 case DLG_STATE_UNCONFIRMED:
2587                                         dlg_starting++;
2588                                 break;
2589                                 case DLG_STATE_EARLY:
2590                                         dlg_connecting++;
2591                                 break;
2592                                 case DLG_STATE_CONFIRMED_NA:
2593                                         dlg_answering++;
2594                                 break;
2595                                 case DLG_STATE_CONFIRMED:
2596                                         dlg_ongoing++;
2597                                 break;
2598                                 default:
2599                                         LM_DBG("not active - state: %d\n", dlg->state);
2600                         }
2601                 }
2602                 dlg_unlock( d_table, &(d_table->entries[i]) );
2603         }
2604
2605         if (rpc->add(c, "{", &h) < 0) {
2606                 rpc->fault(c, 500, "Server failure");
2607                 return;
2608         }
2609
2610         rpc->struct_add(h, "ddddd",
2611                 "starting", dlg_starting,
2612                 "connecting", dlg_connecting,
2613                 "answering", dlg_answering,
2614                 "ongoing", dlg_ongoing,
2615                 "all", dlg_starting + dlg_connecting + dlg_answering + dlg_ongoing);
2616 }
2617
2618 /*!
2619  * \brief Helper function that outputs matching dialogs via the RPC interface
2620  *
2621  * \param rpc RPC node that should be filled
2622  * \param c RPC void pointer
2623  * \param with_context if 1 then the dialog context will be also printed
2624  */
2625 static void rpc_dlg_list_match_ex(rpc_t *rpc, void *c, int with_context)
2626 {
2627         dlg_cell_t *dlg = NULL;
2628         int i = 0;
2629         str mkey = {NULL, 0};
2630         str mop = {NULL, 0};
2631         str mval = {NULL, 0};
2632         str sval = {NULL, 0};
2633         int n = 0;
2634         int m = 0;
2635         int vkey = 0;
2636         int vop = 0;
2637         int matched = 0;
2638         regex_t mre;
2639         regmatch_t pmatch;
2640
2641         i = rpc->scan(c, "SSS", &mkey, &mop, &mval);
2642         if (i < 3) {
2643                 LM_ERR("unable to read required parameters (%d)\n", i);
2644                 rpc->fault(c, 500, "Invalid parameters");
2645                 return;
2646         }
2647         if(mkey.s==NULL || mkey.len<=0 || mop.s==NULL || mop.len<=0
2648                         || mval.s==NULL || mval.len<=0) {
2649                 LM_ERR("invalid parameters (%d)\n", i);
2650                 rpc->fault(c, 500, "Invalid parameters");
2651                 return;
2652         }
2653         if(mkey.len==4 && strncmp(mkey.s, "ruri", mkey.len)==0) {
2654                 vkey = 0;
2655         } else if(mkey.len==4 && strncmp(mkey.s, "furi", mkey.len)==0) {
2656                 vkey = 1;
2657         } else if(mkey.len==4 && strncmp(mkey.s, "turi", mkey.len)==0) {
2658                 vkey = 2;
2659         } else if(mkey.len==5 && strncmp(mkey.s, "callid", mkey.len)==0) {
2660                 vkey = 3;
2661         } else {
2662                 LM_ERR("invalid key %.*s\n", mkey.len, mkey.s);
2663                 rpc->fault(c, 500, "Invalid matching key parameter");
2664                 return;
2665         }
2666         if(mop.len!=2) {
2667                 LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2668                 rpc->fault(c, 500, "Invalid matching operator parameter");
2669                 return;
2670
2671         }
2672         if(strncmp(mop.s, "eq", 2)==0) {
2673                 vop = 0;
2674         } else if(strncmp(mop.s, "re", 2)==0) {
2675                 vop = 1;
2676                 memset(&mre, 0, sizeof(regex_t));
2677                 if (regcomp(&mre, mval.s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
2678                         LM_ERR("failed to compile regex: %.*s\n", mval.len, mval.s);
2679                         rpc->fault(c, 500, "Invalid matching value parameter");
2680                         return;
2681                 }
2682         } else if(strncmp(mop.s, "sw", 2)==0) {
2683                 vop = 2;
2684         } else {
2685                 LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2686                 rpc->fault(c, 500, "Invalid matching operator parameter");
2687                 return;
2688         }
2689         if(rpc->scan(c, "*d", &n)<1) {
2690                 n = 0;
2691         }
2692
2693         for(i=0; i<d_table->size; i++) {
2694                 dlg_lock(d_table, &(d_table->entries[i]));
2695                 for(dlg=d_table->entries[i].first; dlg!=NULL; dlg=dlg->next) {
2696                         matched = 0;
2697                         switch(vkey) {
2698                                 case 0:
2699                                         sval = dlg->req_uri;
2700                                 break;
2701                                 case 1:
2702                                         sval = dlg->from_uri;
2703                                 break;
2704                                 case 2:
2705                                         sval = dlg->to_uri;
2706                                 break;
2707                                 case 3:
2708                                         sval = dlg->callid;
2709                                 break;
2710                         }
2711                         switch(vop) {
2712                                 case 0:
2713                                         /* string comparison */
2714                                         if(mval.len==sval.len
2715                                                         && strncmp(mval.s, sval.s, mval.len)==0) {
2716                                                 matched = 1;
2717                                         }
2718                                 break;
2719                                 case 1:
2720                                         /* regexp matching */
2721                                         if(regexec(&mre, sval.s, 1, &pmatch, 0)==0) {
2722                                                 matched = 1;
2723                                         }
2724                                 break;
2725                                 case 2:
2726                                         /* starts with */
2727                                         if(mval.len<=sval.len
2728                                                         && strncmp(mval.s, sval.s, mval.len)==0) {
2729                                                 matched = 1;
2730                                         }
2731                                 break;
2732                         }
2733                         if (matched==1) {
2734                                 m++;
2735                                 internal_rpc_print_dlg(rpc, c, dlg, with_context);
2736                                 if(n>0 && m==n) {
2737                                         break;
2738                                 }
2739                         }
2740                 }
2741                 dlg_unlock(d_table, &(d_table->entries[i]));
2742                 if(n>0 && m==n) {
2743                         break;
2744                 }
2745         }
2746         if(vop == 1) {
2747                 regfree(&mre);
2748         }
2749
2750         if(m==0) {
2751                 rpc->fault(c, 404, "Not found");
2752                 return;
2753         }
2754 }
2755
2756 /*!
2757  * \brief Print matching dialogs
2758  */
2759 static void rpc_dlg_list_match(rpc_t *rpc, void *c)
2760 {
2761         rpc_dlg_list_match_ex(rpc, c, 0);
2762 }
2763
2764 /*!
2765  * \brief Print matching dialogs wih context
2766  */
2767 static void rpc_dlg_list_match_ctx(rpc_t *rpc, void *c)
2768 {
2769         rpc_dlg_list_match_ex(rpc, c, 1);
2770 }
2771
2772 static rpc_export_t rpc_methods[] = {
2773         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, RET_ARRAY},
2774         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, RET_ARRAY},
2775         {"dlg.list_match", rpc_dlg_list_match, rpc_dlg_list_match_doc, RET_ARRAY},
2776         {"dlg.list_match_ctx", rpc_dlg_list_match_ctx, rpc_dlg_list_match_ctx_doc, RET_ARRAY},
2777         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
2778         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
2779         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
2780         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
2781         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, RET_ARRAY},
2782         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
2783         {"dlg.terminate_dlg", rpc_dlg_terminate_dlg, rpc_dlg_terminate_dlg_doc, 0},
2784         {"dlg.stats_active", rpc_dlg_stats_active, rpc_dlg_stats_active_doc, 0},
2785         {"dlg.is_alive",  rpc_dlg_is_alive, rpc_dlg_is_alive_doc, 0},
2786         {0, 0, 0, 0}
2787 };