app_jsdt: removed dead code
[sip-router] / src / modules / app_jsdt / app_jsdt_api.c
1 /**
2  * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "../../core/dprint.h"
29 #include "../../core/pvar.h"
30 #include "../../core/sr_module.h"
31 #include "../../core/mem/shm.h"
32 #include "../../core/rpc.h"
33 #include "../../core/rpc_lookup.h"
34
35 #include "duktape.h"
36 #include "app_jsdt_kemi_export.h"
37 #include "app_jsdt_api.h"
38
39 #define SRJSDT_FALSE 0
40 #define SRJSDT_TRUE 1
41
42 void jsdt_sr_kemi_register_libs(duk_context *J);
43
44 typedef struct _sr_jsdt_env
45 {
46         duk_context *J;
47         duk_context *JJ;
48         sip_msg_t *msg;
49         unsigned int flags;
50         unsigned int nload; /* number of scripts loaded */
51 } sr_jsdt_env_t;
52
53 static sr_jsdt_env_t _sr_J_env = {0};
54
55 str _sr_jsdt_load_file = STR_NULL;
56
57 static int *_sr_jsdt_reload_version = NULL;
58 static int _sr_jsdt_local_version = 0;
59
60 /**
61  *
62  */
63 sr_jsdt_env_t *jsdt_sr_env_get(void)
64 {
65         return &_sr_J_env;
66 }
67
68 /**
69  *
70  */
71 int jsdt_sr_initialized(void)
72 {
73         if(_sr_J_env.J==NULL)
74                 return 0;
75
76         return 1;
77 }
78
79 /**
80  *
81  */
82 #define JSDT_SR_EXIT_THROW_STR "~~ksr~exit~~"
83 #define JSDT_SR_EXIT_EXEC_STR "throw '" JSDT_SR_EXIT_THROW_STR "';"
84
85 static str _sr_kemi_jsdt_exit_string = str_init(JSDT_SR_EXIT_THROW_STR);
86
87 /**
88  *
89  */
90 str* sr_kemi_jsdt_exit_string_get(void)
91 {
92         return &_sr_kemi_jsdt_exit_string;
93 }
94
95 /**
96  *
97  */
98 int app_jsdt_return_int(duk_context *J, int v)
99 {
100         duk_push_int(J, v);
101         return 1;
102 }
103
104 /**
105  *
106  */
107 int app_jsdt_return_error(duk_context *J)
108 {
109         duk_push_int(J, -1);
110         return 1;
111 }
112
113 /**
114  *
115  */
116 int app_jsdt_return_boolean(duk_context *J, int b)
117 {
118         if(b==SRJSDT_FALSE)
119                 duk_push_boolean(J, SRJSDT_FALSE);
120         else
121                 duk_push_boolean(J, SRJSDT_TRUE);
122         return 1;
123 }
124
125 /**
126  *
127  */
128 int app_jsdt_return_false(duk_context *J)
129 {
130         duk_push_boolean(J, SRJSDT_FALSE);
131         return 1;
132 }
133
134 /**
135  *
136  */
137 int app_jsdt_return_true(duk_context *J)
138 {
139         duk_push_boolean(J, SRJSDT_TRUE);
140         return 1;
141 }
142
143 /**
144  *
145  */
146 int sr_kemi_jsdt_return_int(duk_context *J, sr_kemi_t *ket, int rc)
147 {
148         if(ket->rtype==SR_KEMIP_INT) {
149                 duk_push_int(J, rc);
150                 return 1;
151         }
152         if(ket->rtype==SR_KEMIP_BOOL && rc!=SR_KEMI_FALSE) {
153                 return app_jsdt_return_true(J);
154         }
155         return app_jsdt_return_false(J);
156 }
157
158
159 /**
160  *
161  */
162 static int jsdt_sr_pv_get(duk_context *J)
163 {
164         str pvn;
165         pv_spec_t *pvs;
166         pv_value_t val;
167         sr_jsdt_env_t *env_J;
168         int pl;
169
170         env_J = jsdt_sr_env_get();
171
172         pvn.s = (char*)duk_to_string(J, 0);
173         if(pvn.s==NULL || env_J->msg==NULL)
174                 return 0;
175
176         pvn.len = strlen(pvn.s);
177         LM_DBG("pv get: %s\n", pvn.s);
178         pl = pv_locate_name(&pvn);
179         if(pl != pvn.len) {
180                 LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
181                 return 0;
182         }
183         pvs = pv_cache_get(&pvn);
184         if(pvs==NULL) {
185                 LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
186                 return 0;
187         }
188         memset(&val, 0, sizeof(pv_value_t));
189         if(pv_get_spec_value(env_J->msg, pvs, &val) != 0) {
190                 LM_ERR("unable to get pv value for [%s]\n", pvn.s);
191                 return 0;
192         }
193         if(val.flags&PV_VAL_NULL) {
194                 duk_push_string(J, NULL);
195                 return 1;
196         }
197         if(val.flags&PV_TYPE_INT) {
198                 duk_push_int(J, val.ri);
199                 return 1;
200         }
201         duk_push_lstring(J, val.rs.s, val.rs.len);
202         return 1;
203 }
204
205 /**
206  *
207  */
208 static int jsdt_sr_pv_seti (duk_context *J)
209 {
210         str pvn;
211         pv_spec_t *pvs;
212         pv_value_t val;
213         sr_jsdt_env_t *env_J;
214         int pl;
215
216         env_J = jsdt_sr_env_get();
217
218         if(duk_get_top(J)<2) {
219                 LM_ERR("too few parameters [%d]\n", duk_get_top(J));
220                 return 0;
221         }
222         if(!duk_is_number(J, 1)) {
223                 LM_ERR("invalid int parameter\n");
224                 return 0;
225         }
226
227         pvn.s = (char*)duk_to_string(J, 0);
228         if(pvn.s==NULL || env_J->msg==NULL)
229                 return 0;
230
231         pvn.len = strlen(pvn.s);
232         LM_DBG("pv get: %s\n", pvn.s);
233         pl = pv_locate_name(&pvn);
234         if(pl != pvn.len) {
235                 LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
236                 return 0;
237         }
238         pvs = pv_cache_get(&pvn);
239         if(pvs==NULL) {
240                 LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
241                 return 0;
242         }
243
244         memset(&val, 0, sizeof(pv_value_t));
245         val.ri = duk_to_int(J, 1);
246         val.flags |= PV_TYPE_INT|PV_VAL_INT;
247
248         if(pv_set_spec_value(env_J->msg, pvs, 0, &val)<0) {
249                 LM_ERR("unable to set pv [%s]\n", pvn.s);
250                 return 0;
251         }
252
253         return 0;
254 }
255
256 /**
257  *
258  */
259 static int jsdt_sr_pv_sets (duk_context *J)
260 {
261         str pvn;
262         pv_spec_t *pvs;
263         pv_value_t val;
264         sr_jsdt_env_t *env_J;
265         int pl;
266
267         env_J = jsdt_sr_env_get();
268
269         if(duk_get_top(J)<2) {
270                 LM_ERR("too few parameters [%d]\n", duk_get_top(J));
271                 return 0;
272         }
273
274         if(!duk_is_string(J, 1)) {
275                 LM_ERR("invalid str parameter\n");
276                 return 0;
277         }
278
279         pvn.s = (char*)duk_to_string(J, 0);
280         if(pvn.s==NULL || env_J->msg==NULL)
281                 return 0;
282
283         memset(&val, 0, sizeof(pv_value_t));
284         val.rs.s = (char*)duk_to_string(J, 1);
285         val.rs.len = strlen(val.rs.s);
286         val.flags |= PV_VAL_STR;
287
288         pvn.len = strlen(pvn.s);
289         LM_DBG("pv set: %s\n", pvn.s);
290         pl = pv_locate_name(&pvn);
291         if(pl != pvn.len) {
292                 LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
293                 return 0;
294         }
295         pvs = pv_cache_get(&pvn);
296         if(pvs==NULL) {
297                 LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
298                 return 0;
299         }
300         if(pv_set_spec_value(env_J->msg, pvs, 0, &val)<0) {
301                 LM_ERR("unable to set pv [%s]\n", pvn.s);
302                 return 0;
303         }
304
305         return 0;
306 }
307
308 /**
309  *
310  */
311 static int jsdt_sr_pv_unset (duk_context *J)
312 {
313         str pvn;
314         pv_spec_t *pvs;
315         pv_value_t val;
316         sr_jsdt_env_t *env_J;
317         int pl;
318
319         env_J = jsdt_sr_env_get();
320
321         pvn.s = (char*)duk_to_string(J, 0);
322         if(pvn.s==NULL || env_J->msg==NULL)
323                 return 0;
324
325         pvn.len = strlen(pvn.s);
326         LM_DBG("pv unset: %s\n", pvn.s);
327         pl = pv_locate_name(&pvn);
328         if(pl != pvn.len) {
329                 LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
330                 return 0;
331         }
332         pvs = pv_cache_get(&pvn);
333         if(pvs==NULL)
334         {
335                 LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
336                 return 0;
337         }
338         memset(&val, 0, sizeof(pv_value_t));
339         val.flags |= PV_VAL_NULL;
340         if(pv_set_spec_value(env_J->msg, pvs, 0, &val)<0)
341         {
342                 LM_ERR("unable to unset pv [%s]\n", pvn.s);
343                 return 0;
344         }
345
346         return 0;
347 }
348
349 /**
350  *
351  */
352 static int jsdt_sr_pv_is_null (duk_context *J)
353 {
354         str pvn;
355         pv_spec_t *pvs;
356         pv_value_t val;
357         sr_jsdt_env_t *env_J;
358         int pl;
359
360         env_J = jsdt_sr_env_get();
361
362         pvn.s = (char*)duk_to_string(J, 0);
363         if(pvn.s==NULL || env_J->msg==NULL)
364                 return 0;
365
366         pvn.len = strlen(pvn.s);
367         LM_DBG("pv is null test: %s\n", pvn.s);
368         pl = pv_locate_name(&pvn);
369         if(pl != pvn.len) {
370                 LM_ERR("invalid pv [%s] (%d/%d)\n", pvn.s, pl, pvn.len);
371                 return 0;
372         }
373         pvs = pv_cache_get(&pvn);
374         if(pvs==NULL) {
375                 LM_ERR("cannot get pv spec for [%s]\n", pvn.s);
376                 return 0;
377         }
378         memset(&val, 0, sizeof(pv_value_t));
379         if(pv_get_spec_value(env_J->msg, pvs, &val) != 0) {
380                 LM_NOTICE("unable to get pv value for [%s]\n", pvn.s);
381                 duk_push_boolean(J, 1);
382                 return 1;
383         }
384         if(val.flags&PV_VAL_NULL) {
385                 duk_push_boolean(J, 1);
386         } else {
387                 duk_push_boolean(J, 0);
388         }
389         return 1;
390 }
391
392
393 const duk_function_list_entry _sr_kemi_pv_J_Map[] = {
394         { "get", jsdt_sr_pv_get, 1 /* 1 args */ },
395         { "seti", jsdt_sr_pv_seti, 2 /* 2 args */ },
396         { "sets", jsdt_sr_pv_sets, 2 /* 2 args */ },
397         { "unset", jsdt_sr_pv_unset, 1 /* 1 args */ },
398         { "is_null", jsdt_sr_pv_is_null, 1 /* 1 args */ },
399         { NULL, NULL, 0 }
400 };
401
402 /**
403  *
404  */
405 static int jsdt_sr_exit (duk_context *J)
406 {
407         duk_eval_string_noresult(J, JSDT_SR_EXIT_EXEC_STR);
408         return 0;
409 }
410
411 /**
412  *
413  */
414 static int jsdt_sr_drop (duk_context *J)
415 {
416         sr_kemi_core_drop(NULL);
417         duk_eval_string_noresult(J, JSDT_SR_EXIT_EXEC_STR);
418         return 0;
419 }
420
421
422 /**
423  *
424  */
425 static int jsdt_sr_modf (duk_context *J)
426 {
427         int ret;
428         char *jsdtv[MAX_ACTIONS];
429         char *argv[MAX_ACTIONS];
430         int argc;
431         int i;
432         int mod_type;
433         struct run_act_ctx ra_ctx;
434         unsigned modver;
435         struct action *act;
436         sr31_cmd_export_t* expf;
437         sr_jsdt_env_t *env_J;
438
439         ret = 1;
440         act = NULL;
441         argc = 0;
442         memset(jsdtv, 0, MAX_ACTIONS*sizeof(char*));
443         memset(argv, 0, MAX_ACTIONS*sizeof(char*));
444         env_J = jsdt_sr_env_get();
445         if(env_J->msg==NULL)
446                 goto error;
447
448         argc = duk_get_top(J);
449         if(argc==0) {
450                 LM_ERR("name of module function not provided\n");
451                 goto error;
452         }
453         if(argc>=MAX_ACTIONS) {
454                 LM_ERR("too many parameters\n");
455                 goto error;
456         }
457         /* first is function name, then parameters */
458         for(i=0; i<argc; i++) {
459                 if (!duk_is_string(J, i)) {
460                         LM_ERR("invalid parameter type (%d)\n", i);
461                         goto error;
462                 }
463                 jsdtv[i] = (char*)duk_to_string(J, i);
464         }
465         LM_ERR("request to execute cfg function '%s'\n", jsdtv[0]);
466         /* pkg copy only parameters */
467         for(i=1; i<MAX_ACTIONS; i++) {
468                 if(jsdtv[i]!=NULL) {
469                         argv[i] = (char*)pkg_malloc(strlen(jsdtv[i])+1);
470                         if(argv[i]==NULL) {
471                                 LM_ERR("no more pkg\n");
472                                 goto error;
473                         }
474                         strcpy(argv[i], jsdtv[i]);
475                 }
476         }
477
478         expf = find_export_record(jsdtv[0], argc-1, 0, &modver);
479         if (expf==NULL) {
480                 LM_ERR("function '%s' is not available\n", jsdtv[0]);
481                 goto error;
482         }
483         /* check fixups */
484         if (expf->fixup!=NULL && expf->free_fixup==NULL) {
485                 LM_ERR("function '%s' has fixup - cannot be used\n", jsdtv[0]);
486                 goto error;
487         }
488         switch(expf->param_no) {
489                 case 0:
490                         mod_type = MODULE0_T;
491                         break;
492                 case 1:
493                         mod_type = MODULE1_T;
494                         break;
495                 case 2:
496                         mod_type = MODULE2_T;
497                         break;
498                 case 3:
499                         mod_type = MODULE3_T;
500                         break;
501                 case 4:
502                         mod_type = MODULE4_T;
503                         break;
504                 case 5:
505                         mod_type = MODULE5_T;
506                         break;
507                 case 6:
508                         mod_type = MODULE6_T;
509                         break;
510                 case VAR_PARAM_NO:
511                         mod_type = MODULEX_T;
512                         break;
513                 default:
514                         LM_ERR("unknown/bad definition for function '%s' (%d params)\n",
515                                         jsdtv[0], expf->param_no);
516                         goto error;
517         }
518
519         act = mk_action(mod_type,  argc+1   /* number of (type, value) pairs */,
520                                         MODEXP_ST, expf,    /* function */
521                                         NUMBER_ST, argc-1,  /* parameter number */
522                                         STRING_ST, argv[1], /* param. 1 */
523                                         STRING_ST, argv[2], /* param. 2 */
524                                         STRING_ST, argv[3], /* param. 3 */
525                                         STRING_ST, argv[4], /* param. 4 */
526                                         STRING_ST, argv[5], /* param. 5 */
527                                         STRING_ST, argv[6]  /* param. 6 */
528                         );
529
530         if (act==NULL) {
531                 LM_ERR("action structure could not be created for '%s'\n", jsdtv[0]);
532                 goto error;
533         }
534
535         /* handle fixups */
536         if (expf->fixup) {
537                 if(argc==1) {
538                         /* no parameters */
539                         if(expf->fixup(0, 0)<0) {
540                                 LM_ERR("Error in fixup (0) for '%s'\n", jsdtv[0]);
541                                 goto error;
542                         }
543                 } else {
544                         for(i=1; i<argc; i++) {
545                                 if(expf->fixup(&(act->val[i+1].u.data), i)<0) {
546                                         LM_ERR("Error in fixup (%d) for '%s'\n", i, jsdtv[0]);
547                                         goto error;
548                                 }
549                                 act->val[i+1].type = MODFIXUP_ST;
550                         }
551                 }
552         }
553         init_run_actions_ctx(&ra_ctx);
554         ret = do_action(&ra_ctx, act, env_J->msg);
555
556         /* free fixups */
557         if (expf->fixup) {
558                 for(i=1; i<argc; i++) {
559                         if ((act->val[i+1].type == MODFIXUP_ST) && (act->val[i+1].u.data)) {
560                                 expf->free_fixup(&(act->val[i+1].u.data), i);
561                         }
562                 }
563         }
564         pkg_free(act);
565         for(i=0; i<MAX_ACTIONS; i++) {
566                 if(argv[i]!=NULL) pkg_free(argv[i]);
567                 argv[i] = 0;
568         }
569         duk_push_int(J, ret);
570         return 1;
571
572 error:
573         if(act!=NULL)
574                 pkg_free(act);
575         for(i=0; i<MAX_ACTIONS; i++) {
576                 if(argv[i]!=NULL) pkg_free(argv[i]);
577                 argv[i] = 0;
578         }
579         duk_push_int(J, -1);
580         return 1;
581 }
582
583
584 const duk_function_list_entry _sr_kemi_x_J_Map[] = {
585         { "exit", jsdt_sr_exit, 0 /* 0 args */ },
586         { "drop", jsdt_sr_drop, 0 /* 0 args */ },
587         { "modf", jsdt_sr_modf, DUK_VARARGS /* var args */ },
588         { NULL, NULL, 0 }
589 };
590
591 /**
592  * load a JS file into context
593  */
594 static int jsdt_load_file(duk_context *ctx, const char *filename)
595 {
596         FILE *f;
597         size_t len;
598 #define JSDT_SCRIPT_MAX_SIZE 128*1024
599         char buf[JSDT_SCRIPT_MAX_SIZE];
600
601         f = fopen(filename, "rb");
602         if (f) {
603                 len = fread((void *) buf, 1, sizeof(buf), f);
604                 fclose(f);
605                 if(len>0) {
606                         duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
607                 } else {
608                         LM_ERR("empty content\n");
609                         return -1;
610                 }
611         } else {
612                 LM_ERR("cannot open file\n");
613                 return -1;
614         }
615         return 0;
616 }
617 /**
618  *
619  */
620 int jsdt_sr_init_mod(void)
621 {
622         if(_sr_jsdt_reload_version == NULL) {
623                 _sr_jsdt_reload_version = (int*)shm_malloc(sizeof(int));
624                 if(_sr_jsdt_reload_version == NULL) {
625                         LM_ERR("failed to allocated reload version\n");
626                         return -1;
627                 }
628                 *_sr_jsdt_reload_version = 0;
629         }
630         memset(&_sr_J_env, 0, sizeof(sr_jsdt_env_t));
631
632         return 0;
633 }
634
635 /**
636  *
637  */
638 int jsdt_kemi_load_script(void)
639 {
640         if(jsdt_load_file(_sr_J_env.JJ, _sr_jsdt_load_file.s)<0) {
641                 LM_ERR("failed to load js script file: %.*s\n",
642                                 _sr_jsdt_load_file.len, _sr_jsdt_load_file.s);
643                 return -1;
644         }
645         if (duk_peval(_sr_J_env.JJ) != 0) {
646                 LM_ERR("failed running: %s\n", duk_safe_to_string(_sr_J_env.JJ, -1));
647                 duk_pop(_sr_J_env.JJ);  /* ignore result */
648                 return -1;
649         }
650         duk_pop(_sr_J_env.JJ);  /* ignore result */
651         return 0;
652 }
653 /**
654  *
655  */
656 int jsdt_sr_init_child(void)
657 {
658         memset(&_sr_J_env, 0, sizeof(sr_jsdt_env_t));
659         _sr_J_env.J = duk_create_heap_default();
660         if(_sr_J_env.J==NULL) {
661                 LM_ERR("cannot create JS context (exec)\n");
662                 return -1;
663         }
664         jsdt_sr_kemi_register_libs(_sr_J_env.J);
665         if(_sr_jsdt_load_file.s != NULL && _sr_jsdt_load_file.len>0) {
666                 _sr_J_env.JJ = duk_create_heap_default();
667                 if(_sr_J_env.JJ==NULL) {
668                         LM_ERR("cannot create load JS context (load)\n");
669                         return -1;
670                 }
671                 jsdt_sr_kemi_register_libs(_sr_J_env.JJ);
672                 LM_DBG("loading js script file: %.*s\n",
673                                 _sr_jsdt_load_file.len, _sr_jsdt_load_file.s);
674                 if(jsdt_kemi_load_script()<0) {
675                         return -1;
676                 }
677         }
678         LM_DBG("JS initialized!\n");
679         return 0;
680 }
681
682 /**
683  *
684  */
685 void jsdt_sr_destroy(void)
686 {
687         if(_sr_J_env.J!=NULL) {
688                 duk_destroy_heap(_sr_J_env.J);
689                 _sr_J_env.J = NULL;
690         }
691         if(_sr_J_env.JJ!=NULL) {
692                 duk_destroy_heap(_sr_J_env.JJ);
693                 _sr_J_env.JJ = NULL;
694         }
695         memset(&_sr_J_env, 0, sizeof(sr_jsdt_env_t));
696 }
697
698 /**
699  *
700  */
701 int jsdt_kemi_reload_script(void)
702 {
703         int v;
704         if(_sr_jsdt_load_file.s == NULL && _sr_jsdt_load_file.len<=0) {
705                 LM_WARN("script file path not provided\n");
706                 return -1;
707         }
708         if(_sr_jsdt_reload_version == NULL) {
709                 LM_WARN("reload not enabled\n");
710                 return -1;
711         }
712         if(_sr_J_env.JJ==NULL) {
713                 LM_ERR("load JS context not created\n");
714                 return -1;
715         }
716
717         v = *_sr_jsdt_reload_version;
718         if(v == _sr_jsdt_local_version) {
719                 /* same version */
720                 return 0;
721         }
722         LM_DBG("reloading js script file: %.*s (%d => %d)\n",
723                                 _sr_jsdt_load_file.len, _sr_jsdt_load_file.s,
724                                 _sr_jsdt_local_version, v);
725         jsdt_kemi_load_script();
726         _sr_jsdt_local_version = v;
727         return 0;
728 }
729
730 /**
731  *
732  */
733 int app_jsdt_run_ex(sip_msg_t *msg, char *func, char *p1, char *p2,
734                 char *p3, int emode)
735 {
736         int n;
737         int ret;
738         str txt;
739         sip_msg_t *bmsg;
740
741         if(_sr_J_env.JJ==NULL) {
742                 LM_ERR("js loading state not initialized (call: %s)\n", func);
743                 return -1;
744         }
745         /* check the script version loaded */
746         jsdt_kemi_reload_script();
747
748         LM_DBG("executing js function: [[%s]]\n", func);
749         LM_DBG("js top index is: %d\n", duk_get_top(_sr_J_env.JJ));
750         duk_get_global_string(_sr_J_env.JJ, func);
751         if(!duk_is_function(_sr_J_env.JJ, -1))
752         {
753                 if(emode) {
754                         LM_ERR("no such function [%s] in js scripts\n", func);
755                         LM_ERR("top stack type [%d]\n",
756                                 duk_get_type(_sr_J_env.JJ, -1));
757                         txt.s = (char*)duk_to_string(_sr_J_env.JJ, -1);
758                         LM_ERR("error from JS: %s\n", (txt.s)?txt.s:"unknown");
759                         return -1;
760                 } else {
761                         return 1;
762                 }
763         }
764         n = 0;
765         if(p1!=NULL)
766         {
767                 duk_push_string(_sr_J_env.JJ, p1);
768                 n++;
769                 if(p2!=NULL)
770                 {
771                         duk_push_string(_sr_J_env.JJ, p2);
772                         n++;
773                         if(p3!=NULL)
774                         {
775                                 duk_push_string(_sr_J_env.JJ, p3);
776                                 n++;
777                         }
778                 }
779         }
780         bmsg = _sr_J_env.msg;
781         _sr_J_env.msg = msg;
782         ret = duk_pcall(_sr_J_env.JJ, n);
783         _sr_J_env.msg = bmsg;
784         if(ret!=DUK_EXEC_SUCCESS)
785         {
786                 n = 0;
787                 if (duk_is_error(_sr_J_env.JJ, -1)) {
788                         duk_get_prop_string(_sr_J_env.JJ, -1, "stack");
789                         LM_ERR("error stack from js: %s\n", duk_safe_to_string(_sr_J_env.JJ, -1));
790                         duk_pop(_sr_J_env.JJ);
791                 } else {
792                         txt.s = (char*)duk_safe_to_string(_sr_J_env.JJ, -1);
793                         if(txt.s!=NULL) {
794                                 for(n=0; txt.s[n]!='\0' && _sr_kemi_jsdt_exit_string.s[n]!='\0';
795                                                 n++) {
796                                         if(txt.s[n] != _sr_kemi_jsdt_exit_string.s[n])
797                                                 break;
798                                 }
799                                 if(txt.s[n]!='\0' || _sr_kemi_jsdt_exit_string.s[n]!='\0') {
800                                         LM_ERR("error from js: %s\n", txt.s);
801                                         n = 0;
802                                 } else {
803                                         LM_DBG("ksr error call from js: %s\n", txt.s);
804                                         n = 1;
805                                 }
806                         } else {
807                                 LM_ERR("error from js: unknown\n");
808                         }
809                 }
810                 duk_pop(_sr_J_env.JJ);
811                 if(n==1) {
812                         return 1;
813                 } else {
814                         LM_ERR("error executing: %s (err: %d)\n", func, ret);
815                         return -1;
816                 }
817         }
818         duk_pop(_sr_J_env.JJ);
819
820         return 1;
821 }
822
823 /**
824  *
825  */
826 int app_jsdt_run(sip_msg_t *msg, char *func, char *p1, char *p2,
827                 char *p3)
828 {
829         return app_jsdt_run_ex(msg, func, p1, p2, p3, 1);
830 }
831
832 /**
833  *
834  */
835 int app_jsdt_runstring(sip_msg_t *msg, char *script)
836 {
837         int ret;
838         sip_msg_t *bmsg;
839
840         if(_sr_J_env.JJ==NULL) {
841                 LM_ERR("js loading state not initialized (call: %s)\n", script);
842                 return -1;
843         }
844
845         jsdt_kemi_reload_script();
846
847         LM_DBG("running js string: [[%s]]\n", script);
848         LM_DBG("js top index is: %d\n", duk_get_top(_sr_J_env.JJ));
849         bmsg = _sr_J_env.msg;
850         _sr_J_env.msg = msg;
851         duk_push_string(_sr_J_env.JJ, script);
852         ret = duk_peval(_sr_J_env.JJ);
853         if(ret != 0) {
854                 LM_ERR("JS failed running: %s\n", duk_safe_to_string(_sr_J_env.JJ, -1));
855         }
856         duk_pop(_sr_J_env.JJ);  /* ignore result */
857
858         _sr_J_env.msg = bmsg;
859         return (ret==0)?1:-1;
860 }
861
862 /**
863  *
864  */
865 int app_jsdt_dostring(sip_msg_t *msg, char *script)
866 {
867         int ret;
868         sip_msg_t *bmsg;
869
870         LM_DBG("executing js string: [[%s]]\n", script);
871         LM_DBG("JS top index is: %d\n", duk_get_top(_sr_J_env.J));
872         bmsg = _sr_J_env.msg;
873         _sr_J_env.msg = msg;
874         duk_push_string(_sr_J_env.J, script);
875         ret = duk_peval(_sr_J_env.J);
876         if(ret != 0) {
877                 LM_ERR("JS failed running: %s\n", duk_safe_to_string(_sr_J_env.J, -1));
878         }
879         duk_pop(_sr_J_env.J);  /* ignore result */
880         _sr_J_env.msg = bmsg;
881         return (ret==0)?1:-1;
882 }
883
884 /**
885  *
886  */
887 int app_jsdt_dofile(sip_msg_t *msg, char *script)
888 {
889         int ret;
890         sip_msg_t *bmsg;
891
892         LM_DBG("executing js file: [[%s]]\n", script);
893         LM_DBG("JS top index is: %d\n", duk_get_top(_sr_J_env.J));
894         bmsg = _sr_J_env.msg;
895         _sr_J_env.msg = msg;
896         if(jsdt_load_file(_sr_J_env.J, script)<0) {
897                 LM_ERR("failed to load js script file: %s\n", script);
898                 return -1;
899         }
900         ret = duk_peval(_sr_J_env.J);
901         if(ret != 0) {
902                 LM_ERR("JS failed running: %s\n", duk_safe_to_string(_sr_J_env.J, -1));
903         }
904         duk_pop(_sr_J_env.J);  /* ignore result */
905
906         _sr_J_env.msg = bmsg;
907         return (ret==0)?1:-1;
908 }
909
910 /**
911  *
912  */
913 int sr_kemi_jsdt_exec_func_ex(duk_context *J, sr_kemi_t *ket)
914 {
915         int i;
916         int argc;
917         int ret;
918         str *fname;
919         str *mname;
920         sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX];
921         sr_jsdt_env_t *env_J;
922
923         env_J = jsdt_sr_env_get();
924
925         if(env_J==NULL || env_J->msg==NULL || ket==NULL) {
926                 LM_ERR("invalid JS environment attributes or parameters\n");
927                 return app_jsdt_return_false(J);
928         }
929
930         fname = &ket->fname;
931         mname = &ket->mname;
932
933         argc = duk_get_top(J);
934         if(argc==0 && ket->ptypes[0]==SR_KEMIP_NONE) {
935                 ret = ((sr_kemi_fm_f)(ket->func))(env_J->msg);
936                 return sr_kemi_jsdt_return_int(J, ket, ret);
937         }
938         if(argc==0 && ket->ptypes[0]!=SR_KEMIP_NONE) {
939                 LM_ERR("invalid number of parameters for: %.*s.%.*s\n",
940                                 mname->len, mname->s, fname->len, fname->s);
941                 return app_jsdt_return_false(J);
942         }
943
944         if(argc>SR_KEMI_PARAMS_MAX) {
945                 LM_ERR("too many parameters for: %.*s.%.*s\n",
946                                 mname->len, mname->s, fname->len, fname->s);
947                 return app_jsdt_return_false(J);
948         }
949
950         memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t));
951         for(i=0; i<SR_KEMI_PARAMS_MAX; i++) {
952                 if(ket->ptypes[i]==SR_KEMIP_NONE) {
953                         break;
954                 } else if(ket->ptypes[i]==SR_KEMIP_STR) {
955                         vps[i].s.s = (char*)duk_to_string(J, i);
956                         vps[i].s.len = strlen(vps[i].s.s);
957                         LM_DBG("param[%d] for: %.*s is str: %.*s\n", i,
958                                 fname->len, fname->s, vps[i].s.len, vps[i].s.s);
959                 } else if(ket->ptypes[i]==SR_KEMIP_INT) {
960                         vps[i].n = duk_to_int(J, i);
961                         LM_DBG("param[%d] for: %.*s is int: %d\n", i,
962                                 fname->len, fname->s, vps[i].n);
963                 } else {
964                         LM_ERR("unknown parameter type %d (%d)\n", ket->ptypes[i], i);
965                         return app_jsdt_return_false(J);
966                 }
967         }
968
969         switch(i) {
970                 case 1:
971                         if(ket->ptypes[0]==SR_KEMIP_INT) {
972                                 ret = ((sr_kemi_fmn_f)(ket->func))(env_J->msg, vps[0].n);
973                                 return sr_kemi_jsdt_return_int(J, ket, ret);
974                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
975                                 ret = ((sr_kemi_fms_f)(ket->func))(env_J->msg, &vps[0].s);
976                                 return sr_kemi_jsdt_return_int(J, ket, ret);
977                         } else {
978                                 LM_ERR("invalid parameters for: %.*s\n",
979                                                 fname->len, fname->s);
980                                 return app_jsdt_return_false(J);
981                         }
982                 break;
983                 case 2:
984                         if(ket->ptypes[0]==SR_KEMIP_INT) {
985                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
986                                         ret = ((sr_kemi_fmnn_f)(ket->func))(env_J->msg, vps[0].n, vps[1].n);
987                                         return sr_kemi_jsdt_return_int(J, ket, ret);
988                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
989                                         ret = ((sr_kemi_fmns_f)(ket->func))(env_J->msg, vps[0].n, &vps[1].s);
990                                         return sr_kemi_jsdt_return_int(J, ket, ret);
991                                 } else {
992                                         LM_ERR("invalid parameters for: %.*s\n",
993                                                         fname->len, fname->s);
994                                         return app_jsdt_return_false(J);
995                                 }
996                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
997                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
998                                         ret = ((sr_kemi_fmsn_f)(ket->func))(env_J->msg, &vps[0].s, vps[1].n);
999                                         return sr_kemi_jsdt_return_int(J, ket, ret);
1000                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
1001                                         ret = ((sr_kemi_fmss_f)(ket->func))(env_J->msg, &vps[0].s, &vps[1].s);
1002                                         return sr_kemi_jsdt_return_int(J, ket, ret);
1003                                 } else {
1004                                         LM_ERR("invalid parameters for: %.*s\n",
1005                                                         fname->len, fname->s);
1006                                         return app_jsdt_return_false(J);
1007                                 }
1008                         } else {
1009                                 LM_ERR("invalid parameters for: %.*s\n",
1010                                                 fname->len, fname->s);
1011                                 return app_jsdt_return_false(J);
1012                         }
1013                 break;
1014                 case 3:
1015                         if(ket->ptypes[0]==SR_KEMIP_INT) {
1016                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
1017                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
1018                                                 ret = ((sr_kemi_fmnnn_f)(ket->func))(env_J->msg,
1019                                                                 vps[0].n, vps[1].n, vps[2].n);
1020                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1021                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
1022                                                 ret = ((sr_kemi_fmnns_f)(ket->func))(env_J->msg,
1023                                                                 vps[0].n, vps[1].n, &vps[2].s);
1024                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1025                                         } else {
1026                                                 LM_ERR("invalid parameters for: %.*s\n",
1027                                                                 fname->len, fname->s);
1028                                                 return app_jsdt_return_false(J);
1029                                         }
1030                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
1031                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
1032                                                 ret = ((sr_kemi_fmnsn_f)(ket->func))(env_J->msg,
1033                                                                 vps[0].n, &vps[1].s, vps[2].n);
1034                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1035                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
1036                                                 ret = ((sr_kemi_fmnss_f)(ket->func))(env_J->msg,
1037                                                                 vps[0].n, &vps[1].s, &vps[2].s);
1038                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1039                                         } else {
1040                                                 LM_ERR("invalid parameters for: %.*s\n",
1041                                                                 fname->len, fname->s);
1042                                                 return app_jsdt_return_false(J);
1043                                         }
1044                                 } else {
1045                                         LM_ERR("invalid parameters for: %.*s\n",
1046                                                         fname->len, fname->s);
1047                                         return app_jsdt_return_false(J);
1048                                 }
1049                         } else if(ket->ptypes[0]==SR_KEMIP_STR) {
1050                                 if(ket->ptypes[1]==SR_KEMIP_INT) {
1051                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
1052                                                 ret = ((sr_kemi_fmsnn_f)(ket->func))(env_J->msg,
1053                                                                 &vps[0].s, vps[1].n, vps[2].n);
1054                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1055                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
1056                                                 ret = ((sr_kemi_fmsns_f)(ket->func))(env_J->msg,
1057                                                                 &vps[0].s, vps[1].n, &vps[2].s);
1058                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1059                                         } else {
1060                                                 LM_ERR("invalid parameters for: %.*s\n",
1061                                                                 fname->len, fname->s);
1062                                                 return app_jsdt_return_false(J);
1063                                         }
1064                                 } else if(ket->ptypes[1]==SR_KEMIP_STR) {
1065                                         if(ket->ptypes[2]==SR_KEMIP_INT) {
1066                                                 ret = ((sr_kemi_fmssn_f)(ket->func))(env_J->msg,
1067                                                                 &vps[0].s, &vps[1].s, vps[2].n);
1068                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1069                                         } else if(ket->ptypes[2]==SR_KEMIP_STR) {
1070                                                 ret = ((sr_kemi_fmsss_f)(ket->func))(env_J->msg,
1071                                                                 &vps[0].s, &vps[1].s, &vps[2].s);
1072                                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1073                                         } else {
1074                                                 LM_ERR("invalid parameters for: %.*s\n",
1075                                                                 fname->len, fname->s);
1076                                                 return app_jsdt_return_false(J);
1077                                         }
1078                                 } else {
1079                                         LM_ERR("invalid parameters for: %.*s\n",
1080                                                         fname->len, fname->s);
1081                                         return app_jsdt_return_false(J);
1082                                 }
1083                         } else {
1084                                 LM_ERR("invalid parameters for: %.*s\n",
1085                                                 fname->len, fname->s);
1086                                 return app_jsdt_return_false(J);
1087                         }
1088                 break;
1089                 case 4:
1090                         if(ket->ptypes[0]==SR_KEMIP_STR
1091                                         || ket->ptypes[1]==SR_KEMIP_STR
1092                                         || ket->ptypes[2]==SR_KEMIP_STR
1093                                         || ket->ptypes[3]==SR_KEMIP_STR) {
1094                                 ret = ((sr_kemi_fmssss_f)(ket->func))(env_J->msg,
1095                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s);
1096                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1097                         } else if(ket->ptypes[0]==SR_KEMIP_STR
1098                                         || ket->ptypes[1]==SR_KEMIP_STR
1099                                         || ket->ptypes[2]==SR_KEMIP_INT
1100                                         || ket->ptypes[3]==SR_KEMIP_INT) {
1101                                 ret = ((sr_kemi_fmssnn_f)(ket->func))(env_J->msg,
1102                                                 &vps[0].s, &vps[1].s, vps[2].n, vps[3].n);
1103                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1104                         } else {
1105                                 LM_ERR("invalid parameters for: %.*s\n",
1106                                                 fname->len, fname->s);
1107                                 return app_jsdt_return_false(J);
1108                         }
1109                 break;
1110                 case 5:
1111                         if(ket->ptypes[0]==SR_KEMIP_STR
1112                                         || ket->ptypes[1]==SR_KEMIP_STR
1113                                         || ket->ptypes[2]==SR_KEMIP_STR
1114                                         || ket->ptypes[3]==SR_KEMIP_STR
1115                                         || ket->ptypes[4]==SR_KEMIP_STR) {
1116                                 ret = ((sr_kemi_fmsssss_f)(ket->func))(env_J->msg,
1117                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s,
1118                                                 &vps[4].s);
1119                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1120                         } else {
1121                                 LM_ERR("invalid parameters for: %.*s\n",
1122                                                 fname->len, fname->s);
1123                                 return app_jsdt_return_false(J);
1124                         }
1125                 break;
1126                 case 6:
1127                         if(ket->ptypes[0]==SR_KEMIP_STR
1128                                         || ket->ptypes[1]==SR_KEMIP_STR
1129                                         || ket->ptypes[2]==SR_KEMIP_STR
1130                                         || ket->ptypes[3]==SR_KEMIP_STR
1131                                         || ket->ptypes[4]==SR_KEMIP_STR
1132                                         || ket->ptypes[5]==SR_KEMIP_STR) {
1133                                 ret = ((sr_kemi_fmssssss_f)(ket->func))(env_J->msg,
1134                                                 &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s,
1135                                                 &vps[4].s, &vps[5].s);
1136                                 return sr_kemi_jsdt_return_int(J, ket, ret);
1137                         } else {
1138                                 LM_ERR("invalid parameters for: %.*s\n",
1139                                                 fname->len, fname->s);
1140                                 return app_jsdt_return_false(J);
1141                         }
1142                 break;
1143                 default:
1144                         LM_ERR("invalid parameters for: %.*s\n",
1145                                         fname->len, fname->s);
1146                         return app_jsdt_return_false(J);
1147         }
1148 }
1149
1150 /**
1151  *
1152  */
1153 int sr_kemi_jsdt_exec_func(duk_context *J, int eidx)
1154 {
1155         sr_kemi_t *ket;
1156
1157         ket = sr_kemi_jsdt_export_get(eidx);
1158         return sr_kemi_jsdt_exec_func_ex(J, ket);
1159 }
1160
1161 /**
1162  *
1163  */
1164 duk_function_list_entry *_sr_J_KSRMethods = NULL;
1165 #define SR_JSDT_KSR_MODULES_SIZE        256
1166 #define SR_JSDT_KSR_METHODS_SIZE        (SR_KEMI_JSDT_EXPORT_SIZE + SR_JSDT_KSR_MODULES_SIZE)
1167
1168
1169 /**
1170  *
1171  */
1172 duk_ret_t dukopen_KSR(duk_context *J)
1173 {
1174         duk_function_list_entry *_sr_crt_J_KSRMethods = NULL;
1175         sr_kemi_module_t *emods = NULL;
1176         int emods_size = 0;
1177         int i;
1178         int k;
1179         int n;
1180         char mname[128];
1181         char malias[256];
1182
1183         _sr_J_KSRMethods = malloc(SR_JSDT_KSR_METHODS_SIZE * sizeof(duk_function_list_entry));
1184         if(_sr_J_KSRMethods==NULL) {
1185                 LM_ERR("no more pkg memory\n");
1186                 return 0;
1187         }
1188         memset(_sr_J_KSRMethods, 0, SR_JSDT_KSR_METHODS_SIZE * sizeof(duk_function_list_entry));
1189
1190         emods_size = sr_kemi_modules_size_get();
1191         emods = sr_kemi_modules_get();
1192
1193         n = 0;
1194         _sr_crt_J_KSRMethods = _sr_J_KSRMethods;
1195         if(emods_size==0 || emods[0].kexp==NULL) {
1196                 LM_ERR("no kemi exports registered\n");
1197                 return 0;
1198         }
1199
1200         for(i=0; emods[0].kexp[i].func!=NULL; i++) {
1201                 LM_DBG("exporting KSR.%s(...)\n", emods[0].kexp[i].fname.s);
1202                 _sr_crt_J_KSRMethods[i].key = emods[0].kexp[i].fname.s;
1203                 _sr_crt_J_KSRMethods[i].value =
1204                         sr_kemi_jsdt_export_associate(&emods[0].kexp[i]);
1205                 if(_sr_crt_J_KSRMethods[i].value == NULL) {
1206                         LM_ERR("failed to associate kemi function with js export\n");
1207                         free(_sr_J_KSRMethods);
1208                         _sr_J_KSRMethods = NULL;
1209                         return 0;
1210                 }
1211                 _sr_crt_J_KSRMethods[i].nargs = DUK_VARARGS;
1212                 n++;
1213         }
1214
1215         duk_push_global_object(J);
1216         duk_push_object(J);  /* -> [ ... global obj ] */
1217         duk_put_function_list(J, -1, _sr_crt_J_KSRMethods);
1218         duk_put_prop_string(J, -2, "KSR");  /* -> [ ... global ] */
1219         duk_pop(J);
1220
1221         /* special modules - pv.get(...) can return int or str */
1222         duk_push_global_object(J);
1223         duk_push_object(J);  /* -> [ ... global obj ] */
1224         duk_put_function_list(J, -1, _sr_kemi_pv_J_Map);
1225         duk_put_prop_string(J, -2, "KSR_pv");  /* -> [ ... global ] */
1226         duk_pop(J);
1227         duk_eval_string_noresult(J, "KSR.pv = KSR_pv;");
1228
1229         duk_push_global_object(J);
1230         duk_push_object(J);  /* -> [ ... global obj ] */
1231         duk_put_function_list(J, -1, _sr_kemi_x_J_Map);
1232         duk_put_prop_string(J, -2, "KSR_x");  /* -> [ ... global ] */
1233         duk_pop(J);
1234         duk_eval_string_noresult(J, "KSR.x = KSR_x;");
1235
1236         /* registered kemi modules */
1237         if(emods_size>1) {
1238                 for(k=1; k<emods_size; k++) {
1239                         n++;
1240                         _sr_crt_J_KSRMethods = _sr_J_KSRMethods + n;
1241                         snprintf(mname, 128, "KSR_%s", emods[k].kexp[0].mname.s);
1242                         for(i=0; emods[k].kexp[i].func!=NULL; i++) {
1243                                 LM_DBG("exporting %s.%s(...)\n", mname,
1244                                                 emods[k].kexp[i].fname.s);
1245                                 _sr_crt_J_KSRMethods[i].key = emods[k].kexp[i].fname.s;
1246                                 _sr_crt_J_KSRMethods[i].value =
1247                                         sr_kemi_jsdt_export_associate(&emods[k].kexp[i]);
1248                                 if(_sr_crt_J_KSRMethods[i].value == NULL) {
1249                                         LM_ERR("failed to associate kemi function with func export\n");
1250                                         free(_sr_J_KSRMethods);
1251                                         _sr_J_KSRMethods = NULL;
1252                                         return 0;
1253                                 }
1254                                 _sr_crt_J_KSRMethods[i].nargs = DUK_VARARGS;
1255                                 n++;
1256                         }
1257
1258                         duk_push_global_object(J);
1259                         duk_push_object(J);  /* -> [ ... global obj ] */
1260                         duk_put_function_list(J, -1, _sr_crt_J_KSRMethods);
1261                         duk_put_prop_string(J, -2, mname);  /* -> [ ... global ] */
1262                         duk_pop(J);
1263                         snprintf(malias, 256, "KSR.%s = KSR_%s;", emods[k].kexp[0].mname.s,
1264                                         emods[k].kexp[0].mname.s);
1265                         duk_eval_string_noresult(J, malias);
1266
1267                         LM_DBG("initializing kemi sub-module: %s (%s)\n", mname,
1268                                         emods[k].kexp[0].mname.s);
1269                 }
1270         }
1271         LM_DBG("module 'KSR' has been initialized\n");
1272         return 1;
1273 }
1274
1275 /**
1276  *
1277  */
1278 void jsdt_sr_kemi_register_libs(duk_context *J)
1279 {
1280         int ret;
1281
1282         duk_push_c_function(J, dukopen_KSR, 0 /*nargs*/);
1283         ret = duk_pcall(J, 0);
1284         if(ret!=DUK_EXEC_SUCCESS) {
1285                 LM_ERR("failed to initialize KSR module\n");
1286         }
1287 }
1288
1289 static const char* app_jsdt_rpc_reload_doc[2] = {
1290         "Reload javascript file",
1291         0
1292 };
1293
1294
1295 static void app_jsdt_rpc_reload(rpc_t* rpc, void* ctx)
1296 {
1297         int v;
1298         void *vh;
1299
1300         if(_sr_jsdt_load_file.s == NULL && _sr_jsdt_load_file.len<=0) {
1301                 LM_WARN("script file path not provided\n");
1302                 rpc->fault(ctx, 500, "No script file");
1303                 return;
1304         }
1305         if(_sr_jsdt_reload_version == NULL) {
1306                 LM_WARN("reload not enabled\n");
1307                 rpc->fault(ctx, 500, "Reload not enabled");
1308                 return;
1309         }
1310
1311         v = *_sr_jsdt_reload_version;
1312         LM_INFO("marking for reload js script file: %.*s (%d => %d)\n",
1313                                 _sr_jsdt_load_file.len, _sr_jsdt_load_file.s,
1314                                 _sr_jsdt_local_version, v);
1315         *_sr_jsdt_reload_version += 1;
1316
1317         if (rpc->add(ctx, "{", &vh) < 0) {
1318                 rpc->fault(ctx, 500, "Server error");
1319                 return;
1320         }
1321         rpc->struct_add(vh, "dd",
1322                         "old", v,
1323                         "new", *_sr_jsdt_reload_version);
1324 }
1325
1326 static const char* app_jsdt_rpc_api_list_doc[2] = {
1327         "List kemi exports to javascript",
1328         0
1329 };
1330
1331 static void app_jsdt_rpc_api_list(rpc_t* rpc, void* ctx)
1332 {
1333         int i;
1334         int n;
1335         sr_kemi_t *ket;
1336         void* th;
1337         void* sh;
1338         void* ih;
1339
1340         if (rpc->add(ctx, "{", &th) < 0) {
1341                 rpc->fault(ctx, 500, "Internal error root reply");
1342                 return;
1343         }
1344         n = 0;
1345         for(i=0; i<SR_KEMI_JSDT_EXPORT_SIZE; i++) {
1346                 ket = sr_kemi_jsdt_export_get(i);
1347                 if(ket==NULL) continue;
1348                 n++;
1349         }
1350
1351         if(rpc->struct_add(th, "d[",
1352                                 "msize", n,
1353                                 "methods",  &ih)<0)
1354         {
1355                 rpc->fault(ctx, 500, "Internal error array structure");
1356                 return;
1357         }
1358         for(i=0; i<SR_KEMI_JSDT_EXPORT_SIZE; i++) {
1359                 ket = sr_kemi_jsdt_export_get(i);
1360                 if(ket==NULL) continue;
1361                 if(rpc->struct_add(ih, "{", "func", &sh)<0) {
1362                         rpc->fault(ctx, 500, "Internal error internal structure");
1363                         return;
1364                 }
1365                 if(rpc->struct_add(sh, "SSSS",
1366                                 "ret", sr_kemi_param_map_get_name(ket->rtype),
1367                                 "module", &ket->mname,
1368                                 "name", &ket->fname,
1369                                 "params", sr_kemi_param_map_get_params(ket->ptypes))<0) {
1370                         LM_ERR("failed to add the structure with attributes (%d)\n", i);
1371                         rpc->fault(ctx, 500, "Internal error creating dest struct");
1372                         return;
1373                 }
1374         }
1375 }
1376
1377 rpc_export_t app_jsdt_rpc_cmds[] = {
1378         {"app_jsdt.reload", app_jsdt_rpc_reload,
1379                 app_jsdt_rpc_reload_doc, 0},
1380         {"app_jsdt.api_list", app_jsdt_rpc_api_list,
1381                 app_jsdt_rpc_api_list_doc, 0},
1382         {0, 0, 0, 0}
1383 };
1384
1385 /**
1386  * register RPC commands
1387  */
1388 int app_jsdt_init_rpc(void)
1389 {
1390         if (rpc_register_array(app_jsdt_rpc_cmds)!=0)
1391         {
1392                 LM_ERR("failed to register RPC commands\n");
1393                 return -1;
1394         }
1395         return 0;
1396 }