5df35de40ad1e0aae2314f7cc67fb2762631d7a8
[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 /**
1215  *
1216  */
1217 static int w_dlg_set_timeout(struct sip_msg *msg, char *pto, char *phe, char *phi)
1218 {
1219         int to = 0;
1220         unsigned int he = 0;
1221         unsigned int hi = 0;
1222         dlg_cell_t *dlg = NULL;
1223
1224         if(fixup_get_ivalue(msg, (gparam_p)pto, &to)!=0)
1225         {
1226                 LM_ERR("no timeout value\n");
1227                 return -1;
1228         }
1229         if(to<=0) {
1230                 LM_ERR("invalid timeout value: %d\n", to);
1231                 return -1;
1232         }
1233         if(phe!=NULL)
1234         {
1235                 if(phi==NULL) {
1236                         LM_ERR("invalid number of parameters\n");
1237                         return -1;
1238                 }
1239                 if(fixup_get_ivalue(msg, (gparam_p)phe, (int*)&he)!=0)
1240                 {
1241                         LM_ERR("no hash entry value value\n");
1242                         return -1;
1243                 }
1244                 if(fixup_get_ivalue(msg, (gparam_p)phi, (int*)&hi)!=0)
1245                 {
1246                         LM_ERR("no hash id value value\n");
1247                         return -1;
1248                 }
1249                 dlg = dlg_lookup(he, hi);
1250         } else {
1251                 dlg = dlg_get_msg_dialog(msg);
1252         }
1253
1254         if(dlg==NULL)
1255         {
1256                 LM_DBG("no dialog found\n");
1257                 return -1;
1258         }
1259
1260         if(update_dlg_timeout(dlg, to) != 0)
1261                 return -1;
1262
1263         return 1;
1264 }
1265
1266 /**
1267  *
1268  */
1269 static int ki_dlg_set_property(sip_msg_t *msg, str *pval)
1270 {
1271         dlg_ctx_t *dctx;
1272         dlg_cell_t *d;
1273
1274         if(pval->len<=0) {
1275                 LM_ERR("empty property value\n");
1276                 return -1;
1277         }
1278         if ( (dctx=dlg_get_dlg_ctx())==NULL )
1279                 return -1;
1280
1281         if(pval->len==6 && strncmp(pval->s, "ka-src", 6)==0) {
1282                 dctx->iflags |= DLG_IFLAG_KA_SRC;
1283                 d = dlg_get_by_iuid(&dctx->iuid);
1284                 if(d!=NULL) {
1285                         d->iflags |= DLG_IFLAG_KA_SRC;
1286                         dlg_release(d);
1287                 }
1288         } else if(pval->len==6 && strncmp(pval->s, "ka-dst", 6)==0) {
1289                 dctx->iflags |= DLG_IFLAG_KA_DST;
1290                 d = dlg_get_by_iuid(&dctx->iuid);
1291                 if(d!=NULL) {
1292                         d->iflags |= DLG_IFLAG_KA_DST;
1293                         dlg_release(d);
1294                 }
1295         } else if(pval->len==15 && strncmp(pval->s, "timeout-noreset", 15)==0) {
1296                 dctx->iflags |= DLG_IFLAG_TIMER_NORESET;
1297                 d = dlg_get_by_iuid(&dctx->iuid);
1298                 if(d!=NULL) {
1299                         d->iflags |= DLG_IFLAG_TIMER_NORESET;
1300                         dlg_release(d);
1301                 }
1302         } else {
1303                 LM_ERR("unknown property value [%.*s]\n", pval->len, pval->s);
1304                 return -1;
1305         }
1306
1307         return 1;
1308 }
1309
1310 /**
1311  *
1312  */
1313 static int w_dlg_set_property(struct sip_msg *msg, char *prop, char *s2)
1314 {
1315         str val;
1316
1317         if(fixup_get_svalue(msg, (gparam_t*)prop, &val)!=0)
1318         {
1319                 LM_ERR("no property value\n");
1320                 return -1;
1321         }
1322
1323         return ki_dlg_set_property(msg, &val);
1324 }
1325
1326 static int w_dlg_set_timeout_by_profile3(struct sip_msg *msg, char *profile,
1327                                         char *value, char *timeout_str) 
1328 {
1329         pv_elem_t *pve = NULL;
1330         str val_s;
1331
1332         pve = (pv_elem_t *) value;
1333
1334         if(pve != NULL && ((struct dlg_profile_table *) profile)->has_value) {
1335                 if(pv_printf_s(msg,pve, &val_s) != 0 || 
1336                    !val_s.s || val_s.len == 0) {
1337                         LM_WARN("cannot get string for value\n");
1338                         return -1;
1339                 }
1340         }
1341
1342         if(dlg_set_timeout_by_profile((struct dlg_profile_table *) profile,
1343                                    &val_s, atoi(timeout_str)) != 0)
1344                 return -1;
1345
1346         return 1;
1347 }
1348
1349 static int w_dlg_set_timeout_by_profile2(struct sip_msg *msg, 
1350                                          char *profile, char *timeout_str)
1351 {
1352         return w_dlg_set_timeout_by_profile3(msg, profile, NULL, timeout_str);
1353 }
1354
1355 void dlg_ka_timer_exec(unsigned int ticks, void* param)
1356 {
1357         dlg_ka_run(ticks);
1358 }
1359
1360 void dlg_clean_timer_exec(unsigned int ticks, void* param)
1361 {
1362         dlg_clean_run(ticks);
1363         remove_expired_remote_profiles(time(NULL));
1364 }
1365
1366 static int fixup_dlg_bye(void** param, int param_no)
1367 {
1368         char *val;
1369         int n = 0;
1370
1371         if (param_no==1) {
1372                 val = (char*)*param;
1373                 if (strcasecmp(val,"all")==0) {
1374                         n = 0;
1375                 } else if (strcasecmp(val,"caller")==0) {
1376                         n = 1;
1377                 } else if (strcasecmp(val,"callee")==0) {
1378                         n = 2;
1379                 } else {
1380                         LM_ERR("invalid param \"%s\"\n", val);
1381                         return E_CFG;
1382                 }
1383                 pkg_free(*param);
1384                 *param=(void*)(long)n;
1385         } else {
1386                 LM_ERR("called with parameter != 1\n");
1387                 return E_BUG;
1388         }
1389         return 0;
1390 }
1391
1392 static int fixup_dlg_refer(void** param, int param_no)
1393 {
1394         char *val;
1395         int n = 0;
1396
1397         if (param_no==1) {
1398                 val = (char*)*param;
1399                 if (strcasecmp(val,"caller")==0) {
1400                         n = 1;
1401                 } else if (strcasecmp(val,"callee")==0) {
1402                         n = 2;
1403                 } else {
1404                         LM_ERR("invalid param \"%s\"\n", val);
1405                         return E_CFG;
1406                 }
1407                 pkg_free(*param);
1408                 *param=(void*)(long)n;
1409         } else if (param_no==2) {
1410                 return fixup_spve_null(param, 1);
1411         } else {
1412                 LM_ERR("called with parameter idx %d\n", param_no);
1413                 return E_BUG;
1414         }
1415         return 0;
1416 }
1417
1418 static int fixup_dlg_bridge(void** param, int param_no)
1419 {
1420         if (param_no>=1 && param_no<=3) {
1421                 return fixup_spve_null(param, 1);
1422         } else {
1423                 LM_ERR("called with parameter idx %d\n", param_no);
1424                 return E_BUG;
1425         }
1426         return 0;
1427 }
1428
1429 static int ki_dlg_get(sip_msg_t *msg, str *sc, str *sf, str *st)
1430 {
1431         dlg_cell_t *dlg = NULL;
1432         unsigned int dir = 0;
1433
1434         if(sc==NULL || sc->s==NULL || sc->len == 0) {
1435                 LM_ERR("invalid Call-ID parameter\n");
1436                 return -1;
1437         }
1438         if(sf==NULL || sf->s==NULL || sf->len == 0) {
1439                 LM_ERR("invalid From tag parameter\n");
1440                 return -1;
1441         }
1442         if(st==NULL || st->s==NULL || st->len == 0) {
1443                 LM_ERR("invalid To tag parameter\n");
1444                 return -1;
1445         }
1446
1447         dlg = get_dlg(sc, sf, st, &dir);
1448         if(dlg==NULL)
1449                 return -1;
1450         /* set shorcut to dialog internal unique id */
1451         _dlg_ctx.iuid.h_entry = dlg->h_entry;
1452         _dlg_ctx.iuid.h_id = dlg->h_id;
1453         _dlg_ctx.dir = dir;
1454         dlg_release(dlg);
1455         return 1;
1456 }
1457
1458 static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
1459 {
1460         str sc = {0,0};
1461         str sf = {0,0};
1462         str st = {0,0};
1463
1464         if(ci==0 || ft==0 || tt==0)
1465         {
1466                 LM_ERR("invalid parameters\n");
1467                 return -1;
1468         }
1469
1470         if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
1471         {
1472                 LM_ERR("unable to get Call-ID\n");
1473                 return -1;
1474         }
1475
1476         if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
1477         {
1478                 LM_ERR("unable to get From tag\n");
1479                 return -1;
1480         }
1481
1482         if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
1483         {
1484                 LM_ERR("unable to get To Tag\n");
1485                 return -1;
1486         }
1487         if(st.s==NULL || st.len == 0)
1488         {
1489                 LM_ERR("invalid To tag parameter\n");
1490                 return -1;
1491         }
1492
1493         return ki_dlg_get(msg, &sc, &sf, &st);
1494 }
1495
1496 /**
1497  *
1498  */
1499 static int w_dlg_remote_profile(sip_msg_t *msg, char *cmd, char *pname,
1500                 char *pval, char *puid, char *expires)
1501 {
1502         str scmd;
1503         str sname;
1504         str sval;
1505         str suid;
1506         int ival;
1507         int ret;
1508
1509         if(fixup_get_svalue(msg, (gparam_t*)cmd, &scmd)!=0) {
1510                 LM_ERR("unable to get command\n");
1511                 return -1;
1512         }
1513         if(fixup_get_svalue(msg, (gparam_t*)pname, &sname)!=0) {
1514                 LM_ERR("unable to get profile name\n");
1515                 return -1;
1516         }
1517         if(fixup_get_svalue(msg, (gparam_t*)pval, &sval)!=0) {
1518                 LM_ERR("unable to get profile value\n");
1519                 return -1;
1520         }
1521         if(fixup_get_svalue(msg, (gparam_t*)puid, &suid)!=0) {
1522                 LM_ERR("unable to get profile uid\n");
1523                 return -1;
1524         }
1525         if(fixup_get_ivalue(msg, (gparam_t*)expires, &ival)!=0) {
1526                 LM_ERR("no hash entry value value\n");
1527                 return -1;
1528         }
1529
1530         ret = dlg_cmd_remote_profile(&scmd, &sname, &sval, &suid, (time_t)ival, 0);
1531         if(ret==0)
1532                 return 1;
1533         return ret;
1534 }
1535
1536 static int fixup_dlg_remote_profile(void** param, int param_no)
1537 {
1538         if(param_no>=1 && param_no<=4)
1539                 return fixup_spve_null(param, 1);
1540         if(param_no==5)
1541                 return fixup_igp_null(param, 1);
1542         return 0;
1543 }
1544
1545 /**
1546  *
1547  */
1548 static int ki_dlg_bye(sip_msg_t *msg, str *side)
1549 {
1550         dlg_cell_t *dlg = NULL;
1551
1552         dlg = dlg_get_ctx_dialog();
1553         if(dlg==NULL)
1554                 return -1;
1555
1556         if(side->len==6 && strncasecmp(side->s, "caller", 6)==0)
1557         {
1558                 if(dlg_bye(dlg, NULL, DLG_CALLER_LEG)!=0)
1559                         goto error;
1560                 goto done;
1561         } else if(side->len==6 && strncasecmp(side->s, "callee", 6)==0) {
1562                 if(dlg_bye(dlg, NULL, DLG_CALLEE_LEG)!=0)
1563                         goto error;
1564                 goto done;
1565         } else {
1566                 if(dlg_bye_all(dlg, NULL)!=0)
1567                         goto error;
1568                 goto done;
1569         }
1570
1571 done:
1572         dlg_release(dlg);
1573         return 1;
1574
1575 error:
1576         dlg_release(dlg);
1577         return -1;
1578 }
1579
1580 /**
1581  *
1582  */
1583 static int ki_dlg_set_timeout_id(sip_msg_t *msg, int to, int he, int hi)
1584 {
1585         dlg_cell_t *dlg = NULL;
1586
1587         dlg = dlg_lookup(he, hi);
1588         if(dlg==NULL) {
1589                 LM_DBG("no dialog found\n");
1590                 return -1;
1591         }
1592
1593         /* update_dlg_timeout() does dlg_release() */
1594         if(update_dlg_timeout(dlg, to) != 0)
1595                 return -1;
1596
1597         return 1;
1598 }
1599
1600 /**
1601  *
1602  */
1603 static int ki_dlg_set_timeout(sip_msg_t *msg, int to)
1604 {
1605         dlg_cell_t *dlg = NULL;
1606
1607         dlg = dlg_get_msg_dialog(msg);
1608         if(dlg==NULL) {
1609                 LM_DBG("no dialog found\n");
1610                 return -1;
1611         }
1612
1613         /* update_dlg_timeout() does dlg_release() */
1614         if(update_dlg_timeout(dlg, to) != 0)
1615                 return -1;
1616
1617         return 1;
1618
1619 }
1620
1621 /**
1622  *
1623  */
1624 static int ki_set_dlg_profile_static(sip_msg_t *msg, str *sprofile)
1625 {
1626         struct dlg_profile_table *profile = NULL;
1627
1628         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1629                 LM_ERR("invalid profile identifier\n");
1630                 return -1;
1631         }
1632         profile = search_dlg_profile( sprofile );
1633         if (profile==NULL) {
1634                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1635                 return -1;
1636         }
1637
1638         return w_set_dlg_profile_helper(msg, profile, NULL);
1639 }
1640
1641 /**
1642  *
1643  */
1644 static int ki_set_dlg_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1645 {
1646         struct dlg_profile_table *profile = NULL;
1647
1648         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1649                 LM_ERR("invalid profile identifier\n");
1650                 return -1;
1651         }
1652         profile = search_dlg_profile( sprofile );
1653         if (profile==NULL) {
1654                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1655                 return -1;
1656         }
1657
1658         return w_set_dlg_profile_helper(msg, profile, svalue);
1659 }
1660
1661 /**
1662  *
1663  */
1664 static int ki_unset_dlg_profile_static(sip_msg_t *msg, str *sprofile)
1665 {
1666         struct dlg_profile_table *profile = NULL;
1667
1668         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1669                 LM_ERR("invalid profile identifier\n");
1670                 return -1;
1671         }
1672         profile = search_dlg_profile( sprofile );
1673         if (profile==NULL) {
1674                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1675                 return -1;
1676         }
1677
1678         return w_unset_dlg_profile_helper(msg, profile, NULL);
1679 }
1680
1681 /**
1682  *
1683  */
1684 static int ki_unset_dlg_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1685 {
1686         struct dlg_profile_table *profile = NULL;
1687
1688         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1689                 LM_ERR("invalid profile identifier\n");
1690                 return -1;
1691         }
1692         profile = search_dlg_profile( sprofile );
1693         if (profile==NULL) {
1694                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1695                 return -1;
1696         }
1697
1698         return w_unset_dlg_profile_helper(msg, profile, svalue);
1699 }
1700
1701 /**
1702  *
1703  */
1704 static int ki_is_in_profile_static(sip_msg_t *msg, str *sprofile)
1705 {
1706         struct dlg_profile_table *profile = NULL;
1707
1708         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1709                 LM_ERR("invalid profile identifier\n");
1710                 return -1;
1711         }
1712         profile = search_dlg_profile( sprofile );
1713         if (profile==NULL) {
1714                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1715                 return -1;
1716         }
1717
1718         return w_is_in_profile_helper(msg, profile, NULL);
1719 }
1720
1721 /**
1722  *
1723  */
1724 static int ki_is_in_profile(sip_msg_t *msg, str *sprofile, str *svalue)
1725 {
1726         struct dlg_profile_table *profile = NULL;
1727
1728         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1729                 LM_ERR("invalid profile identifier\n");
1730                 return -1;
1731         }
1732         profile = search_dlg_profile( sprofile );
1733         if (profile==NULL) {
1734                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1735                 return -1;
1736         }
1737
1738         return w_is_in_profile_helper(msg, profile, svalue);
1739 }
1740
1741 /**
1742  *
1743  */
1744 static int ki_get_profile_size_static(sip_msg_t *msg, str *sprofile, str *spv)
1745 {
1746         struct dlg_profile_table *profile = NULL;
1747         pv_spec_t *pvs = NULL;
1748
1749         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1750                 LM_ERR("invalid profile identifier\n");
1751                 return -1;
1752         }
1753         if(spv==NULL || spv->s==NULL || spv->len<=0) {
1754                 LM_ERR("invalid destination var name\n");
1755                 return -1;
1756         }
1757         profile = search_dlg_profile( sprofile );
1758         if (profile==NULL) {
1759                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1760                 return -1;
1761         }
1762         pvs = pv_cache_get(spv);
1763         if(pvs==NULL) {
1764                 LM_ERR("cannot get pv spec for [%.*s]\n", spv->len, spv->s);
1765                 return -1;
1766         }
1767         if (pvs->type!=PVT_AVP && pvs->type!=PVT_SCRIPTVAR) {
1768                 LM_ERR("return must be an AVP or SCRIPT VAR!\n");
1769                 return -1;
1770         }
1771
1772         return w_get_profile_size_helper(msg, profile, NULL, pvs);
1773 }
1774
1775 /**
1776  *
1777  */
1778 static int ki_get_profile_size(sip_msg_t *msg, str *sprofile, str *svalue,
1779                 str *spv)
1780 {
1781         struct dlg_profile_table *profile = NULL;
1782         pv_spec_t *pvs = NULL;
1783
1784         if(sprofile==NULL || sprofile->s==NULL || sprofile->len<=0) {
1785                 LM_ERR("invalid profile identifier\n");
1786                 return -1;
1787         }
1788         if(spv==NULL || spv->s==NULL || spv->len<=0) {
1789                 LM_ERR("invalid destination var name\n");
1790                 return -1;
1791         }
1792         profile = search_dlg_profile( sprofile );
1793         if (profile==NULL) {
1794                 LM_CRIT("profile <%.*s> not defined\n", sprofile->len, sprofile->s);
1795                 return -1;
1796         }
1797         pvs = pv_cache_get(spv);
1798         if(pvs==NULL) {
1799                 LM_ERR("cannot get pv spec for [%.*s]\n", spv->len, spv->s);
1800                 return -1;
1801         }
1802         if (pvs->type!=PVT_AVP && pvs->type!=PVT_SCRIPTVAR) {
1803                 LM_ERR("return must be an AVP or SCRIPT VAR!\n");
1804                 return -1;
1805         }
1806
1807         return w_get_profile_size_helper(msg, profile, svalue, pvs);
1808 }
1809
1810 /**
1811  *
1812  */
1813 static int ki_dlg_db_load_callid(sip_msg_t *msg, str *callid)
1814 {
1815         int ret;
1816
1817         ret = load_dialog_info_from_db(dlg_hash_size, db_fetch_rows, 1, callid);
1818
1819         if(ret==0) return 1;
1820         return ret;
1821 }
1822
1823 /**
1824  *
1825  */
1826 static int w_dlg_db_load_callid(sip_msg_t *msg, char *ci, char *p2)
1827 {
1828         str sc = {0,0};
1829
1830         if(ci==0) {
1831                 LM_ERR("invalid parameters\n");
1832                 return -1;
1833         }
1834
1835         if(fixup_get_svalue(msg, (gparam_t*)ci, &sc)!=0) {
1836                 LM_ERR("unable to get Call-ID\n");
1837                 return -1;
1838         }
1839
1840         return ki_dlg_db_load_callid(msg, &sc);
1841 }
1842
1843 /**
1844  *
1845  */
1846 static int ki_dlg_db_load_extra(sip_msg_t *msg)
1847 {
1848         int ret;
1849
1850         ret = load_dialog_info_from_db(dlg_hash_size, db_fetch_rows, 2, NULL);
1851
1852         if(ret==0) return 1;
1853         return ret;
1854 }
1855
1856 /**
1857  *
1858  */
1859 static int w_dlg_db_load_extra(sip_msg_t *msg, char *p1, char *p2)
1860 {
1861         return ki_dlg_db_load_extra(msg);
1862 }
1863
1864 /**
1865  *
1866  */
1867 static int ki_dlg_var_sets(sip_msg_t *msg, str *name, str *val)
1868 {
1869         dlg_cell_t *dlg;
1870         int ret;
1871
1872         dlg = dlg_get_msg_dialog(msg);
1873         ret = set_dlg_variable_unsafe(dlg, name, val);
1874         if(dlg) {
1875                 dlg_release(dlg);
1876         }
1877
1878         return (ret==0)?1:ret;
1879 }
1880
1881 /**
1882  *
1883  */
1884 static sr_kemi_xval_t _sr_kemi_dialog_xval = {0};
1885
1886 /**
1887  *
1888  */
1889 static sr_kemi_xval_t* ki_dlg_var_get_mode(sip_msg_t *msg, str *name, int rmode)
1890 {
1891         dlg_cell_t *dlg;
1892         str *pval;
1893
1894         memset(&_sr_kemi_dialog_xval, 0, sizeof(sr_kemi_xval_t));
1895
1896         dlg = dlg_get_msg_dialog(msg);
1897         if(dlg==NULL) {
1898                 sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
1899                 return &_sr_kemi_dialog_xval;
1900         }
1901         pval = get_dlg_variable(dlg, name);
1902         if(pval==NULL || pval->s==NULL) {
1903                 sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
1904                 goto done;
1905         }
1906
1907         _sr_kemi_dialog_xval.vtype = SR_KEMIP_STR;
1908         _sr_kemi_dialog_xval.v.s = *pval;
1909
1910 done:
1911         dlg_release(dlg);
1912         return &_sr_kemi_dialog_xval;
1913 }
1914
1915 /**
1916  *
1917  */
1918 static sr_kemi_xval_t* ki_dlg_var_get(sip_msg_t *msg, str *name)
1919 {
1920         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_NONE);
1921 }
1922
1923 /**
1924  *
1925  */
1926 static sr_kemi_xval_t* ki_dlg_var_gete(sip_msg_t *msg, str *name)
1927 {
1928         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_EMPTY);
1929 }
1930 /**
1931  *
1932  */
1933 static sr_kemi_xval_t* ki_dlg_var_getw(sip_msg_t *msg, str *name)
1934 {
1935         return ki_dlg_var_get_mode(msg, name, SR_KEMI_XVAL_NULL_PRINT);
1936 }
1937
1938 /**
1939  *
1940  */
1941 static int ki_dlg_var_rm(sip_msg_t *msg, str *name)
1942 {
1943         dlg_cell_t *dlg;
1944
1945         dlg = dlg_get_msg_dialog(msg);
1946         set_dlg_variable_unsafe(dlg, name, NULL);
1947         return 1;
1948 }
1949
1950 /**
1951  *
1952  */
1953 static int ki_dlg_var_is_null(sip_msg_t *msg, str *name)
1954 {
1955         dlg_cell_t *dlg;
1956         str *pval;
1957
1958         dlg = dlg_get_msg_dialog(msg);
1959         if(dlg==NULL) {
1960                 return 1;
1961         }
1962         pval = get_dlg_variable(dlg, name);
1963         if(pval==NULL || pval->s==NULL) {
1964                 return 1;
1965         }
1966         return -1;
1967 }
1968
1969 /**
1970  *
1971  */
1972 /* clang-format off */
1973 static sr_kemi_t sr_kemi_dialog_exports[] = {
1974         { str_init("dialog"), str_init("dlg_manage"),
1975                 SR_KEMIP_INT, dlg_manage,
1976                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1977                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1978         },
1979         { str_init("dialog"), str_init("dlg_bye"),
1980                 SR_KEMIP_INT, ki_dlg_bye,
1981                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1982                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1983         },
1984         { str_init("dialog"), str_init("is_known_dlg"),
1985                 SR_KEMIP_INT, is_known_dlg,
1986                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1987                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1988         },
1989         { str_init("dialog"), str_init("dlg_set_timeout"),
1990                 SR_KEMIP_INT, ki_dlg_set_timeout,
1991                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
1992                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1993         },
1994         { str_init("dialog"), str_init("dlg_set_timeout_id"),
1995                 SR_KEMIP_INT, ki_dlg_set_timeout_id,
1996                 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_INT,
1997                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1998         },
1999         { str_init("dialog"), str_init("dlg_set_property"),
2000                 SR_KEMIP_INT, ki_dlg_set_property,
2001                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2002                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2003         },
2004         { str_init("dialog"), str_init("dlg_get"),
2005                 SR_KEMIP_INT, ki_dlg_get,
2006                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2007                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2008         },
2009         { str_init("dialog"), str_init("set_dlg_profile_static"),
2010                 SR_KEMIP_INT, ki_set_dlg_profile_static,
2011                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2012                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2013         },
2014         { str_init("dialog"), str_init("set_dlg_profile"),
2015                 SR_KEMIP_INT, ki_set_dlg_profile,
2016                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2017                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2018         },
2019         { str_init("dialog"), str_init("unset_dlg_profile_static"),
2020                 SR_KEMIP_INT, ki_unset_dlg_profile_static,
2021                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2022                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2023         },
2024         { str_init("dialog"), str_init("unset_dlg_profile"),
2025                 SR_KEMIP_INT, ki_unset_dlg_profile,
2026                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2027                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2028         },
2029         { str_init("dialog"), str_init("is_in_profile_static"),
2030                 SR_KEMIP_INT, ki_is_in_profile_static,
2031                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2032                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2033         },
2034         { str_init("dialog"), str_init("is_in_profile"),
2035                 SR_KEMIP_INT, ki_is_in_profile,
2036                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2037                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2038         },
2039         { str_init("dialog"), str_init("get_profile_size_static"),
2040                 SR_KEMIP_INT, ki_get_profile_size_static,
2041                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2042                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2043         },
2044         { str_init("dialog"), str_init("get_profile_size"),
2045                 SR_KEMIP_INT, ki_get_profile_size,
2046                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
2047                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2048         },
2049         { str_init("dialog"), str_init("dlg_setflag"),
2050                 SR_KEMIP_INT, ki_dlg_setflag,
2051                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2052                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2053         },
2054         { str_init("dialog"), str_init("dlg_resetflag"),
2055                 SR_KEMIP_INT, ki_dlg_resetflag,
2056                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2057                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2058         },
2059         { str_init("dialog"), str_init("dlg_isflagset"),
2060                 SR_KEMIP_INT, ki_dlg_isflagset,
2061                 { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
2062                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2063         },
2064         { str_init("dialog"), str_init("dlg_db_load_callid"),
2065                 SR_KEMIP_INT, ki_dlg_db_load_callid,
2066                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2067                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2068         },
2069         { str_init("dialog"), str_init("dlg_db_load_extra"),
2070                 SR_KEMIP_INT, ki_dlg_db_load_extra,
2071                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
2072                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2073         },
2074         { str_init("dialog"), str_init("var_sets"),
2075                 SR_KEMIP_INT, ki_dlg_var_sets,
2076                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
2077                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2078         },
2079         { str_init("dialog"), str_init("var_get"),
2080                 SR_KEMIP_XVAL, ki_dlg_var_get,
2081                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2082                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2083         },
2084         { str_init("dialog"), str_init("var_gete"),
2085                 SR_KEMIP_XVAL, ki_dlg_var_gete,
2086                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2087                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2088         },
2089         { str_init("dialog"), str_init("var_getw"),
2090                 SR_KEMIP_XVAL, ki_dlg_var_getw,
2091                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2092                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2093         },
2094         { str_init("dialog"), str_init("var_rm"),
2095                 SR_KEMIP_INT, ki_dlg_var_rm,
2096                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2097                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2098         },
2099         { str_init("dialog"), str_init("var_is_null"),
2100                 SR_KEMIP_INT, ki_dlg_var_is_null,
2101                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
2102                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
2103         },
2104
2105         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
2106 };
2107 /* clang-format on */
2108
2109 /**
2110  *
2111  */
2112 int mod_register(char *path, int *dlflags, void *p1, void *p2)
2113 {
2114         sr_kemi_modules_add(sr_kemi_dialog_exports);
2115         return 0;
2116 }
2117
2118 /**************************** RPC functions ******************************/
2119 /*!
2120  * \brief Helper method that outputs a dialog via the RPC interface
2121  * \see rpc_print_dlg
2122  * \param rpc RPC node that should be filled
2123  * \param c RPC void pointer
2124  * \param dlg printed dialog
2125  * \param with_context if 1 then the dialog context will be also printed
2126  * \return 0 on success, -1 on failure
2127  */
2128 static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, dlg_cell_t *dlg,
2129                 int with_context)
2130 {
2131         rpc_cb_ctx_t rpc_cb;
2132         void *h, *sh, *ssh;
2133         dlg_profile_link_t *pl;
2134         dlg_var_t *var;
2135
2136         if (rpc->add(c, "{", &h) < 0) goto error;
2137
2138         rpc->struct_add(h, "dddSSSddddddddd",
2139                 "h_entry", dlg->h_entry,
2140                 "h_id", dlg->h_id,
2141                 "ref", dlg->ref,
2142                 "call-id", &dlg->callid,
2143                 "from_uri", &dlg->from_uri,
2144                 "to_uri", &dlg->to_uri,
2145                 "state", dlg->state,
2146                 "start_ts", dlg->start_ts,
2147                 "init_ts", dlg->init_ts,
2148                 "end_ts", dlg->end_ts,
2149                 "timeout", dlg->tl.timeout ? time(0) + dlg->tl.timeout - get_ticks() : 0,
2150                 "lifetime", dlg->lifetime,
2151                 "dflags", dlg->dflags,
2152                 "sflags", dlg->sflags,
2153                 "iflags", dlg->iflags);
2154
2155         if (rpc->struct_add(h, "{", "caller", &sh) < 0) goto error;
2156         rpc->struct_add(sh, "SSSSS",
2157                 "tag", &dlg->tag[DLG_CALLER_LEG],
2158                 "contact", &dlg->contact[DLG_CALLER_LEG],
2159                 "cseq", &dlg->cseq[DLG_CALLER_LEG],
2160                 "route_set", &dlg->route_set[DLG_CALLER_LEG],
2161                 "socket", dlg->bind_addr[DLG_CALLER_LEG] ? &dlg->bind_addr[DLG_CALLER_LEG]->sock_str : &empty_str);
2162
2163         if (rpc->struct_add(h, "{", "callee", &sh) < 0) goto error;
2164         rpc->struct_add(sh, "SSSSS",
2165                 "tag", &dlg->tag[DLG_CALLEE_LEG],
2166                 "contact", &dlg->contact[DLG_CALLEE_LEG],
2167                 "cseq", &dlg->cseq[DLG_CALLEE_LEG],
2168                 "route_set", &dlg->route_set[DLG_CALLEE_LEG],
2169                 "socket", dlg->bind_addr[DLG_CALLEE_LEG] ? &dlg->bind_addr[DLG_CALLEE_LEG]->sock_str : &empty_str);
2170
2171         if (rpc->struct_add(h, "[", "profiles", &sh) < 0) goto error;
2172         for (pl = dlg->profile_links ; pl && (dlg->state<DLG_STATE_DELETED) ; pl=pl->next) {
2173                 if (pl->profile->has_value) {
2174                         rpc->array_add(sh, "{", &ssh);
2175                         rpc->struct_add(ssh, "S", pl->profile->name.s, &pl->hash_linker.value);
2176                 } else {
2177                         rpc->array_add(sh, "S", &pl->profile->name);
2178                 }
2179         }
2180
2181         if (rpc->struct_add(h, "[", "variables", &sh) < 0) goto error;
2182         for(var=dlg->vars ; var && (dlg->state<DLG_STATE_DELETED) ; var=var->next) {
2183                 rpc->array_add(sh, "{", &ssh);
2184                 rpc->struct_add(ssh, "S", var->key.s, &var->value);
2185         }
2186
2187         if (with_context) {
2188                 rpc_cb.rpc = rpc;
2189                 rpc_cb.c = h;
2190                 run_dlg_callbacks( DLGCB_RPC_CONTEXT, dlg, NULL, NULL, DLG_DIR_NONE, (void *)&rpc_cb);
2191         }
2192
2193         return;
2194 error:
2195         LM_ERR("Failed to add item to RPC response\n");
2196         return;
2197 }
2198
2199 /*!
2200  * \brief Helper function that outputs all dialogs via the RPC interface
2201  * \see rpc_print_dlgs
2202  * \param rpc RPC node that should be filled
2203  * \param c RPC void pointer
2204  * \param with_context if 1 then the dialog context will be also printed
2205  */
2206 static void internal_rpc_print_dlgs(rpc_t *rpc, void *c, int with_context)
2207 {
2208         dlg_cell_t *dlg;
2209         unsigned int i;
2210
2211         for( i=0 ; i<d_table->size ; i++ ) {
2212                 dlg_lock( d_table, &(d_table->entries[i]) );
2213
2214                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
2215                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
2216                 }
2217                 dlg_unlock( d_table, &(d_table->entries[i]) );
2218         }
2219 }
2220
2221 /*!
2222  * \brief Helper function that outputs a dialog via the RPC interface
2223  * \see rpc_print_dlgs
2224  * \param rpc RPC node that should be filled
2225  * \param c RPC void pointer
2226  * \param with_context if 1 then the dialog context will be also printed
2227  */
2228 static void internal_rpc_print_single_dlg(rpc_t *rpc, void *c, int with_context) {
2229         str callid, ft;
2230         str *from_tag = NULL;
2231         dlg_entry_t *d_entry;
2232         dlg_cell_t *dlg;
2233         unsigned int h_entry;
2234
2235         if (rpc->scan(c, ".S", &callid) < 1) return;
2236
2237         h_entry = core_hash( &callid, 0, d_table->size);
2238         d_entry = &(d_table->entries[h_entry]);
2239
2240         if (rpc->scan(c, "*.S", &ft) == 1) {
2241                 from_tag = &ft;
2242         }
2243
2244         dlg_lock( d_table, d_entry);
2245         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
2246                 if (match_downstream_dialog( dlg, &callid, from_tag)==1) {
2247                         internal_rpc_print_dlg(rpc, c, dlg, with_context);
2248                 }
2249         }
2250         dlg_unlock( d_table, d_entry);
2251 }
2252
2253 /*!
2254  * \brief Helper function that outputs the size of a given profile via the RPC interface
2255  * \see rpc_profile_get_size
2256  * \see rpc_profile_w_value_get_size
2257  * \param rpc RPC node that should be filled
2258  * \param c RPC void pointer
2259  * \param profile_name the given profile
2260  * \param value the given profile value
2261  */
2262 static void internal_rpc_profile_get_size(rpc_t *rpc, void *c, str *profile_name,
2263                 str *value) {
2264         unsigned int size;
2265         dlg_profile_table_t *profile;
2266
2267         profile = search_dlg_profile( profile_name );
2268         if (!profile) {
2269                 rpc->fault(c, 404, "Profile not found: %.*s",
2270                         profile_name->len, profile_name->s);
2271                 return;
2272         }
2273         size = get_profile_size(profile, value);
2274         rpc->add(c, "d", size);
2275         return;
2276 }
2277
2278 /*!
2279  * \brief Helper function that outputs the dialogs belonging to a given profile via the RPC interface
2280  * \see rpc_profile_print_dlgs
2281  * \see rpc_profile_w_value_print_dlgs
2282  * \param rpc RPC node that should be filled
2283  * \param c RPC void pointer
2284  * \param profile_name the given profile
2285  * \param value the given profile value
2286  * \param with_context if 1 then the dialog context will be also printed
2287  */
2288 static void internal_rpc_profile_print_dlgs(rpc_t *rpc, void *c, str *profile_name,
2289                 str *value) {
2290         dlg_profile_table_t *profile;
2291         dlg_profile_hash_t *ph;
2292         unsigned int i;
2293
2294         profile = search_dlg_profile( profile_name );
2295         if (!profile) {
2296                 rpc->fault(c, 404, "Profile not found: %.*s",
2297                         profile_name->len, profile_name->s);
2298                 return;
2299         }
2300
2301         /* go through the hash and print the dialogs */
2302         if (profile->has_value==0)
2303                 value=NULL;
2304
2305         lock_get( &profile->lock );
2306         for ( i=0 ; i< profile->size ; i++ ) {
2307                 ph = profile->entries[i].first;
2308                 if(ph) {
2309                         do {
2310                                 if ((!value || (STR_EQ(*value, ph->value))) && ph->dlg) {
2311                                         /* print dialog */
2312                                         internal_rpc_print_dlg(rpc, c, ph->dlg, 0);
2313                                 }
2314                                 /* next */
2315                                 ph=ph->next;
2316                         }while(ph!=profile->entries[i].first);
2317                 }
2318         }
2319         lock_release(&profile->lock);
2320 }
2321
2322 /*
2323  * Wrapper around is_known_dlg().
2324  */
2325
2326 static int w_is_known_dlg(sip_msg_t *msg) {
2327         return  is_known_dlg(msg);
2328 }
2329
2330 static int w_dlg_set_ruri(sip_msg_t *msg, char *p1, char *p2)
2331 {
2332         return  dlg_set_ruri(msg);
2333 }
2334
2335 static const char *rpc_print_dlgs_doc[2] = {
2336         "Print all dialogs", 0
2337 };
2338 static const char *rpc_print_dlgs_ctx_doc[2] = {
2339         "Print all dialogs with associated context", 0
2340 };
2341 static const char *rpc_dlg_list_match_doc[2] = {
2342         "Print matching dialogs", 0
2343 };
2344 static const char *rpc_dlg_list_match_ctx_doc[2] = {
2345         "Print matching dialogs with associated context", 0
2346 };
2347 static const char *rpc_print_dlg_doc[2] = {
2348         "Print dialog based on callid and optionally fromtag", 0
2349 };
2350 static const char *rpc_print_dlg_ctx_doc[2] = {
2351         "Print dialog with associated context based on callid and optionally fromtag", 0
2352 };
2353 static const char *rpc_end_dlg_entry_id_doc[2] = {
2354         "End a given dialog based on [h_entry] [h_id]", 0
2355 };
2356 static const char *rpc_dlg_terminate_dlg_doc[2] = {
2357         "End a given dialog based on callid", 0
2358 };
2359 static const char *rpc_profile_get_size_doc[2] = {
2360         "Returns the number of dialogs belonging to a profile", 0
2361 };
2362 static const char *rpc_profile_print_dlgs_doc[2] = {
2363         "Lists all the dialogs belonging to a profile", 0
2364 };
2365 static const char *rpc_dlg_bridge_doc[2] = {
2366         "Bridge two SIP addresses in a call using INVITE(hold)-REFER-BYE mechanism:"
2367                 " to, from, [outbound SIP proxy]", 0
2368 };
2369 static const char *rpc_dlg_is_alive_doc[2] = {
2370         "Check whether dialog is alive or not", 0
2371 };
2372
2373
2374 static void rpc_print_dlgs(rpc_t *rpc, void *c) {
2375         internal_rpc_print_dlgs(rpc, c, 0);
2376 }
2377 static void rpc_print_dlgs_ctx(rpc_t *rpc, void *c) {
2378         internal_rpc_print_dlgs(rpc, c, 1);
2379 }
2380 static void rpc_print_dlg(rpc_t *rpc, void *c) {
2381         internal_rpc_print_single_dlg(rpc, c, 0);
2382 }
2383 static void rpc_print_dlg_ctx(rpc_t *rpc, void *c) {
2384         internal_rpc_print_single_dlg(rpc, c, 1);
2385 }
2386
2387 static void rpc_dlg_terminate_dlg(rpc_t *rpc,void *c){
2388         str callid = {NULL,0};
2389         str ftag = {NULL,0};
2390         str ttag = {NULL,0};
2391
2392         dlg_cell_t * dlg = NULL;
2393         unsigned int dir;
2394         int ret=0;
2395         dir = 0;
2396
2397
2398         if(rpc->scan(c, ".S.S.S", &callid,&ftag,&ttag)<3) {
2399                 LM_ERR("Unable to read the parameters dlg_terminate_dlg \n" );
2400                 rpc->fault(c, 400, "Need a Callid ,from tag ,to tag");
2401                 return;
2402         }
2403
2404         dlg=get_dlg(&callid, &ftag, &ttag, &dir);
2405
2406         if(dlg==NULL) {
2407                 LM_ERR("Couldnt find callid in dialog '%.*s' \n",callid.len, callid.s);
2408                 rpc->fault(c, 500, "Couldnt find callid in dialog");
2409                 return;
2410         }
2411
2412         LM_DBG("Dialog is found with callid  for terminate rpc '%.*s' \n",
2413                         callid.len, callid.s);
2414
2415         ret=dlg_bye_all(dlg, NULL);
2416
2417         LM_DBG("Dialog bye return code %d \n",ret);
2418
2419         if(ret>=0) {
2420         LM_WARN("Dialog is terminated callid: '%.*s' \n",
2421                         callid.len, callid.s);
2422         dlg_release(dlg);
2423     }
2424 }
2425
2426 static void rpc_dlg_is_alive(rpc_t *rpc, void *c)
2427 {
2428         str callid = {NULL, 0};
2429         str ftag = {NULL, 0};
2430         str ttag = {NULL, 0};
2431
2432         dlg_cell_t *dlg = NULL;
2433         unsigned int dir = 0;
2434         unsigned int state = 0;
2435
2436         if (rpc->scan(c, ".S.S.S", &callid, &ftag, &ttag) < 3) {
2437                 LM_DBG("Unable to read expected parameters\n");
2438                 rpc->fault(c, 400, "Too few parameters (required callid, from-tag, to-tag)");
2439                 return;
2440         }
2441
2442         dlg = get_dlg(&callid, &ftag, &ttag, &dir);
2443
2444         if (dlg == NULL) {
2445                 LM_DBG("Couldnt find dialog with callid: '%.*s'\n", callid.len, callid.s);
2446                 rpc->fault(c, 404, "Dialog not found");
2447                 return;
2448         }
2449         state = dlg->state;
2450     dlg_release(dlg);
2451         if (state != DLG_STATE_CONFIRMED) {
2452                 LM_DBG("Dialog with Call-ID '%.*s' is in state: %d (confirmed: %d)\n",
2453                                 callid.len, callid.s, state, DLG_STATE_CONFIRMED);
2454                 rpc->fault(c, 500, "Dialog not in confirmed state");
2455                 return;
2456         } else {
2457                 rpc->add(c, "s", "Alive");
2458         }
2459 }
2460
2461 static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
2462         unsigned int h_entry, h_id;
2463         dlg_cell_t * dlg = NULL;
2464         str rpc_extra_hdrs = {NULL,0};
2465         int n;
2466
2467         n = rpc->scan(c, "dd", &h_entry, &h_id);
2468         if (n < 2) {
2469                 LM_ERR("unable to read the parameters (%d)\n", n);
2470                 rpc->fault(c, 500, "Invalid parameters");
2471                 return;
2472         }
2473         if(rpc->scan(c, "*S", &rpc_extra_hdrs)<1)
2474         {
2475                 rpc_extra_hdrs.s = NULL;
2476                 rpc_extra_hdrs.len = 0;
2477         }
2478
2479         dlg = dlg_lookup(h_entry, h_id);
2480         if(dlg==NULL) {
2481                 rpc->fault(c, 404, "Dialog not found");
2482                 return;
2483         }
2484
2485         dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
2486         dlg_release(dlg);
2487 }
2488 static void rpc_profile_get_size(rpc_t *rpc, void *c) {
2489         str profile_name = {NULL,0};
2490         str value = {NULL,0};
2491
2492         if (rpc->scan(c, ".S", &profile_name) < 1) return;
2493         if (rpc->scan(c, "*.S", &value) > 0) {
2494                 internal_rpc_profile_get_size(rpc, c, &profile_name, &value);
2495         } else {
2496                 internal_rpc_profile_get_size(rpc, c, &profile_name, NULL);
2497         }
2498         return;
2499 }
2500 static void rpc_profile_print_dlgs(rpc_t *rpc, void *c) {
2501         str profile_name = {NULL,0};
2502         str value = {NULL,0};
2503
2504         if (rpc->scan(c, ".S", &profile_name) < 1) return;
2505         if (rpc->scan(c, "*.S", &value) > 0) {
2506                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, &value);
2507         } else {
2508                 internal_rpc_profile_print_dlgs(rpc, c, &profile_name, NULL);
2509         }
2510         return;
2511 }
2512
2513 static void rpc_dlg_bridge(rpc_t *rpc, void *c) {
2514         str from = {NULL,0};
2515         str to = {NULL,0};
2516         str op = {NULL,0};
2517         str bd = {NULL,0};
2518         int n;
2519
2520         n = rpc->scan(c, "SS", &from, &to);
2521         if (n< 2) {
2522                 LM_ERR("unable to read the parameters (%d)\n", n);
2523                 rpc->fault(c, 500, "Invalid parameters");
2524                 return;
2525         }
2526         if(rpc->scan(c, "*S", &op)<1) {
2527                 op.s = NULL;
2528                 op.len = 0;
2529         } else {
2530                 if(op.len==1 && *op.s=='.') {
2531                         op.s = NULL;
2532                         op.len = 0;
2533                 }
2534                 if(rpc->scan(c, "*S", &bd)<1) {
2535                         bd.s = NULL;
2536                         bd.len = 0;
2537                 } else {
2538                         if(bd.len==1 && *bd.s=='.') {
2539                                 bd.s = NULL;
2540                                 bd.len = 0;
2541                         } else if(bd.len==1 && *bd.s=='_') {
2542                                 bd.s = "";
2543                                 bd.len = 0;
2544                         }
2545                 }
2546         }
2547
2548         dlg_bridge(&from, &to, &op, &bd);
2549 }
2550
2551 static const char *rpc_dlg_stats_active_doc[2] = {
2552         "Get stats about active dialogs", 0
2553 };
2554
2555 /*!
2556  * \brief Print stats of active dialogs
2557  */
2558 static void rpc_dlg_stats_active(rpc_t *rpc, void *c)
2559 {
2560         dlg_cell_t *dlg;
2561         unsigned int i;
2562         int dlg_starting = 0;
2563         int dlg_connecting = 0;
2564         int dlg_answering = 0;
2565         int dlg_ongoing = 0;
2566         void *h;
2567
2568         for( i=0 ; i<d_table->size ; i++ ) {
2569                 dlg_lock( d_table, &(d_table->entries[i]) );
2570
2571                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
2572                         switch(dlg->state) {
2573                                 case DLG_STATE_UNCONFIRMED:
2574                                         dlg_starting++;
2575                                 break;
2576                                 case DLG_STATE_EARLY:
2577                                         dlg_connecting++;
2578                                 break;
2579                                 case DLG_STATE_CONFIRMED_NA:
2580                                         dlg_answering++;
2581                                 break;
2582                                 case DLG_STATE_CONFIRMED:
2583                                         dlg_ongoing++;
2584                                 break;
2585                                 default:
2586                                         LM_DBG("not active - state: %d\n", dlg->state);
2587                         }
2588                 }
2589                 dlg_unlock( d_table, &(d_table->entries[i]) );
2590         }
2591
2592         if (rpc->add(c, "{", &h) < 0) {
2593                 rpc->fault(c, 500, "Server failure");
2594                 return;
2595         }
2596
2597         rpc->struct_add(h, "ddddd",
2598                 "starting", dlg_starting,
2599                 "connecting", dlg_connecting,
2600                 "answering", dlg_answering,
2601                 "ongoing", dlg_ongoing,
2602                 "all", dlg_starting + dlg_connecting + dlg_answering + dlg_ongoing);
2603 }
2604
2605 /*!
2606  * \brief Helper function that outputs matching dialogs via the RPC interface
2607  *
2608  * \param rpc RPC node that should be filled
2609  * \param c RPC void pointer
2610  * \param with_context if 1 then the dialog context will be also printed
2611  */
2612 static void rpc_dlg_list_match_ex(rpc_t *rpc, void *c, int with_context)
2613 {
2614         dlg_cell_t *dlg = NULL;
2615         int i = 0;
2616         str mkey = {NULL, 0};
2617         str mop = {NULL, 0};
2618         str mval = {NULL, 0};
2619         str sval = {NULL, 0};
2620         int n = 0;
2621         int m = 0;
2622         int vkey = 0;
2623         int vop = 0;
2624         int matched = 0;
2625         regex_t mre;
2626         regmatch_t pmatch;
2627
2628         i = rpc->scan(c, "SSS", &mkey, &mop, &mval);
2629         if (i < 3) {
2630                 LM_ERR("unable to read required parameters (%d)\n", i);
2631                 rpc->fault(c, 500, "Invalid parameters");
2632                 return;
2633         }
2634         if(mkey.s==NULL || mkey.len<=0 || mop.s==NULL || mop.len<=0
2635                         || mval.s==NULL || mval.len<=0) {
2636                 LM_ERR("invalid parameters (%d)\n", i);
2637                 rpc->fault(c, 500, "Invalid parameters");
2638                 return;
2639         }
2640         if(mkey.len==4 && strncmp(mkey.s, "ruri", mkey.len)==0) {
2641                 vkey = 0;
2642         } else if(mkey.len==4 && strncmp(mkey.s, "furi", mkey.len)==0) {
2643                 vkey = 1;
2644         } else if(mkey.len==4 && strncmp(mkey.s, "turi", mkey.len)==0) {
2645                 vkey = 2;
2646         } else if(mkey.len==5 && strncmp(mkey.s, "callid", mkey.len)==0) {
2647                 vkey = 3;
2648         } else {
2649                 LM_ERR("invalid key %.*s\n", mkey.len, mkey.s);
2650                 rpc->fault(c, 500, "Invalid matching key parameter");
2651                 return;
2652         }
2653         if(mop.len!=2) {
2654                 LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2655                 rpc->fault(c, 500, "Invalid matching operator parameter");
2656                 return;
2657
2658         }
2659         if(strncmp(mop.s, "eq", 2)==0) {
2660                 vop = 0;
2661         } else if(strncmp(mop.s, "re", 2)==0) {
2662                 vop = 1;
2663                 memset(&mre, 0, sizeof(regex_t));
2664                 if (regcomp(&mre, mval.s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
2665                         LM_ERR("failed to compile regex: %.*s\n", mval.len, mval.s);
2666                         rpc->fault(c, 500, "Invalid matching value parameter");
2667                         return;
2668                 }
2669         } else if(strncmp(mop.s, "sw", 2)==0) {
2670                 vop = 2;
2671         } else {
2672                 LM_ERR("invalid matching operator %.*s\n", mop.len, mop.s);
2673                 rpc->fault(c, 500, "Invalid matching operator parameter");
2674                 return;
2675         }
2676         if(rpc->scan(c, "*d", &n)<1) {
2677                 n = 0;
2678         }
2679
2680         for(i=0; i<d_table->size; i++) {
2681                 dlg_lock(d_table, &(d_table->entries[i]));
2682                 for(dlg=d_table->entries[i].first; dlg!=NULL; dlg=dlg->next) {
2683                         matched = 0;
2684                         switch(vkey) {
2685                                 case 0:
2686                                         sval = dlg->req_uri;
2687                                 break;
2688                                 case 1:
2689                                         sval = dlg->from_uri;
2690                                 break;
2691                                 case 2:
2692                                         sval = dlg->to_uri;
2693                                 break;
2694                                 case 3:
2695                                         sval = dlg->callid;
2696                                 break;
2697                         }
2698                         switch(vop) {
2699                                 case 0:
2700                                         /* string comparison */
2701                                         if(mval.len==sval.len
2702                                                         && strncmp(mval.s, sval.s, mval.len)==0) {
2703                                                 matched = 1;
2704                                         }
2705                                 break;
2706                                 case 1:
2707                                         /* regexp matching */
2708                                         if(regexec(&mre, sval.s, 1, &pmatch, 0)==0) {
2709                                                 matched = 1;
2710                                         }
2711                                 break;
2712                                 case 2:
2713                                         /* starts with */
2714                                         if(mval.len<=sval.len
2715                                                         && strncmp(mval.s, sval.s, mval.len)==0) {
2716                                                 matched = 1;
2717                                         }
2718                                 break;
2719                         }
2720                         if (matched==1) {
2721                                 m++;
2722                                 internal_rpc_print_dlg(rpc, c, dlg, with_context);
2723                                 if(n>0 && m==n) {
2724                                         break;
2725                                 }
2726                         }
2727                 }
2728                 dlg_unlock(d_table, &(d_table->entries[i]));
2729                 if(n>0 && m==n) {
2730                         break;
2731                 }
2732         }
2733         if(vop == 1) {
2734                 regfree(&mre);
2735         }
2736
2737         if(m==0) {
2738                 rpc->fault(c, 404, "Not found");
2739                 return;
2740         }
2741 }
2742
2743 /*!
2744  * \brief Print matching dialogs
2745  */
2746 static void rpc_dlg_list_match(rpc_t *rpc, void *c)
2747 {
2748         rpc_dlg_list_match_ex(rpc, c, 0);
2749 }
2750
2751 /*!
2752  * \brief Print matching dialogs wih context
2753  */
2754 static void rpc_dlg_list_match_ctx(rpc_t *rpc, void *c)
2755 {
2756         rpc_dlg_list_match_ex(rpc, c, 1);
2757 }
2758
2759 static rpc_export_t rpc_methods[] = {
2760         {"dlg.list", rpc_print_dlgs, rpc_print_dlgs_doc, RET_ARRAY},
2761         {"dlg.list_ctx", rpc_print_dlgs_ctx, rpc_print_dlgs_ctx_doc, RET_ARRAY},
2762         {"dlg.list_match", rpc_dlg_list_match, rpc_dlg_list_match_doc, RET_ARRAY},
2763         {"dlg.list_match_ctx", rpc_dlg_list_match_ctx, rpc_dlg_list_match_ctx_doc, RET_ARRAY},
2764         {"dlg.dlg_list", rpc_print_dlg, rpc_print_dlg_doc, 0},
2765         {"dlg.dlg_list_ctx", rpc_print_dlg_ctx, rpc_print_dlg_ctx_doc, 0},
2766         {"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
2767         {"dlg.profile_get_size", rpc_profile_get_size, rpc_profile_get_size_doc, 0},
2768         {"dlg.profile_list", rpc_profile_print_dlgs, rpc_profile_print_dlgs_doc, RET_ARRAY},
2769         {"dlg.bridge_dlg", rpc_dlg_bridge, rpc_dlg_bridge_doc, 0},
2770         {"dlg.terminate_dlg", rpc_dlg_terminate_dlg, rpc_dlg_terminate_dlg_doc, 0},
2771         {"dlg.stats_active", rpc_dlg_stats_active, rpc_dlg_stats_active_doc, 0},
2772         {"dlg.is_alive",  rpc_dlg_is_alive, rpc_dlg_is_alive_doc, 0},
2773         {0, 0, 0, 0}
2774 };