uac: new modparam reg_gc_interval
[sip-router] / src / modules / uac / uac.c
1 /*
2  * Copyright (C) 2005 Voice Sistem SRL
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio uac :: The SIP UA client module
25  * \ingroup uac
26  * Module: \ref uac
27  */
28
29 /*! \defgroup uac The SIP UA Client module
30  *
31  */
32
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38
39 #include "../../core/sr_module.h"
40 #include "../../core/dprint.h"
41 #include "../../core/error.h"
42 #include "../../core/pvar.h"
43 #include "../../core/pt.h"
44 #include "../../core/timer.h"
45 #include "../../core/mem/mem.h"
46 #include "../../core/parser/parse_from.h"
47 #include "../../modules/tm/tm_load.h"
48 #include "../../modules/tm/t_hooks.h"
49 #include "../../core/mod_fix.h"
50 #include "../../core/kemi.h"
51 #include "../../core/rpc.h"
52 #include "../../core/rpc_lookup.h"
53 #include "../../core/rand/kam_rand.h"
54 #include "../../core/cfg/cfg_struct.h"
55 #include "../dialog/dlg_load.h"
56
57 #include "../rr/api.h"
58
59 #include "replace.h"
60 #include "auth.h"
61 #include "uac_send.h"
62 #include "uac_reg.h"
63 #include "api.h"
64
65
66 MODULE_VERSION
67
68
69 /* local variable used for init */
70 static char* restore_mode_str = NULL;
71 static char* auth_username_avp = NULL;
72 static char* auth_realm_avp = NULL;
73 static char* auth_password_avp = NULL;
74 unsigned short restore_from_avp_type;
75 int_str restore_from_avp_name;
76 unsigned short restore_to_avp_type;
77 int_str restore_to_avp_name;
78 static int uac_restore_dlg = 0;
79 static int reg_active_param = 1;
80
81 /* global param variables */
82 str rr_from_param = str_init("vsf");
83 str rr_to_param = str_init("vst");
84 str uac_passwd = str_init("");
85 str restore_from_avp = STR_NULL;
86 str restore_to_avp = STR_NULL;
87 int restore_mode = UAC_AUTO_RESTORE;
88 struct tm_binds uac_tmb;
89 struct rr_binds uac_rrb;
90 pv_spec_t auth_username_spec;
91 pv_spec_t auth_realm_spec;
92 pv_spec_t auth_password_spec;
93
94 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2);
95 static int w_restore_from(struct sip_msg* msg, char* p1, char* p2);
96 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2);
97 static int w_restore_to(struct sip_msg* msg, char* p1, char* p2);
98 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
99 static int w_uac_reg_lookup(struct sip_msg* msg, char* src, char* dst);
100 static int w_uac_reg_status(struct sip_msg* msg, char* src, char* dst);
101 static int w_uac_reg_request_to(struct sip_msg* msg, char* src, char* mode_s);
102 static int w_uac_reg_enable(struct sip_msg* msg, char* pfilter, char* pval);
103 static int w_uac_reg_disable(struct sip_msg* msg, char* pfilter, char* pval);
104 static int w_uac_reg_refresh(struct sip_msg* msg, char* pluuid, char* p2);
105 static int mod_init(void);
106 static void mod_destroy(void);
107 static int child_init(int rank);
108
109 extern int reg_timer_interval;
110 extern int _uac_reg_gc_interval;
111
112 static pv_export_t mod_pvs[] = {
113         { {"uac_req", sizeof("uac_req")-1}, PVT_OTHER, pv_get_uac_req, pv_set_uac_req,
114                 pv_parse_uac_req_name, 0, 0, 0 },
115         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
116 };
117
118
119 /* Exported functions */
120 static cmd_export_t cmds[]={
121         {"uac_replace_from",  (cmd_function)w_replace_from,  2, fixup_spve_spve, 0,
122                 REQUEST_ROUTE | BRANCH_ROUTE },
123         {"uac_replace_from",  (cmd_function)w_replace_from,  1, fixup_spve_spve, 0,
124                 REQUEST_ROUTE | BRANCH_ROUTE },
125         {"uac_restore_from",  (cmd_function)w_restore_from,  0,           0, 0,
126                 REQUEST_ROUTE },
127         {"uac_replace_to",  (cmd_function)w_replace_to,  2, fixup_spve_spve, 0,
128                 REQUEST_ROUTE | BRANCH_ROUTE },
129         {"uac_replace_to",  (cmd_function)w_replace_to,  1, fixup_spve_spve, 0,
130                 REQUEST_ROUTE | BRANCH_ROUTE },
131         {"uac_restore_to",  (cmd_function)w_restore_to,  0, 0, 0, REQUEST_ROUTE },
132         {"uac_auth",      (cmd_function)w_uac_auth,       0, 0, 0, FAILURE_ROUTE },
133         {"uac_req_send",  (cmd_function)w_uac_req_send,   0, 0, 0, ANY_ROUTE},
134         {"uac_reg_lookup",  (cmd_function)w_uac_reg_lookup,  2, fixup_spve_pvar,
135                 fixup_free_spve_pvar, ANY_ROUTE },
136         {"uac_reg_status",  (cmd_function)w_uac_reg_status,  1, fixup_spve_null, 0,
137                 ANY_ROUTE },
138         {"uac_reg_request_to",  (cmd_function)w_uac_reg_request_to,  2,
139                 fixup_spve_igp, fixup_free_spve_igp,
140                 REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE },
141         {"uac_reg_enable",   (cmd_function)w_uac_reg_enable,   2, fixup_spve_spve,
142                 fixup_free_spve_spve, ANY_ROUTE },
143         {"uac_reg_disable",  (cmd_function)w_uac_reg_disable,  2, fixup_spve_spve,
144                 fixup_free_spve_spve, ANY_ROUTE },
145         {"uac_reg_refresh",  (cmd_function)w_uac_reg_refresh,  1, fixup_spve_null,
146                 fixup_free_spve_null, ANY_ROUTE },
147         {"bind_uac", (cmd_function)bind_uac,              1,  0, 0, 0},
148         {0,0,0,0,0,0}
149 };
150
151
152
153 /* Exported parameters */
154 static param_export_t params[] = {
155         {"rr_from_store_param", PARAM_STR,                      &rr_from_param       },
156         {"rr_to_store_param",   PARAM_STR,                      &rr_to_param       },
157         {"restore_mode",        PARAM_STRING,                   &restore_mode_str      },
158         {"restore_dlg",         INT_PARAM,                      &uac_restore_dlg       },
159         {"restore_passwd",      PARAM_STR,                      &uac_passwd       },
160         {"restore_from_avp",    PARAM_STR,                      &restore_from_avp },
161         {"restore_to_avp",      PARAM_STR,                      &restore_to_avp },
162         {"credential",          PARAM_STRING|USE_FUNC_PARAM,    (void*)&add_credential },
163         {"auth_username_avp",   PARAM_STRING,                   &auth_username_avp     },
164         {"auth_realm_avp",      PARAM_STRING,                   &auth_realm_avp },
165         {"auth_password_avp",   PARAM_STRING,                   &auth_password_avp     },
166         {"reg_db_url",          PARAM_STR,                      &reg_db_url       },
167         {"reg_db_table",        PARAM_STR,                      &reg_db_table   },
168         {"reg_contact_addr",    PARAM_STR,                      &reg_contact_addr    },
169         {"reg_timer_interval",  INT_PARAM,                      &reg_timer_interval     },
170         {"reg_retry_interval",  INT_PARAM,                      &reg_retry_interval    },
171         {"reg_keep_callid",     INT_PARAM,                      &reg_keep_callid       },
172         {"reg_random_delay",    INT_PARAM,                      &reg_random_delay      },
173         {"reg_active",  INT_PARAM,                      &reg_active_param      },
174         {"reg_gc_interval",             INT_PARAM,      &_uac_reg_gc_interval   },
175         {0, 0, 0}
176 };
177
178
179
180 struct module_exports exports= {
181         "uac",           /* module name */
182         DEFAULT_DLFLAGS, /* dlopen flags */
183         cmds,            /* cmd exports */
184         params,          /* param exports */
185         0,               /* RPC method exports */
186         mod_pvs,         /* pseudo-variables exports */
187         0,               /* response handling function */
188         mod_init,        /* module initialization function */
189         child_init,      /* per-child init function */
190         mod_destroy
191 };
192
193
194 inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt)
195 {
196         str s;
197         s.s = avp_spec; s.len = strlen(s.s);
198         if (pv_parse_spec(&s, avp)==NULL) {
199                 LM_ERR("malformed or non AVP %s AVP definition\n",txt);
200                 return -1;
201         }
202         return 0;
203 }
204
205
206 static int mod_init(void)
207 {
208         pv_spec_t avp_spec;
209
210         if (restore_mode_str && *restore_mode_str) {
211                 if (strcasecmp(restore_mode_str,"none")==0) {
212                         restore_mode = UAC_NO_RESTORE;
213                 } else if (strcasecmp(restore_mode_str,"manual")==0) {
214                         restore_mode = UAC_MANUAL_RESTORE;
215                 } else if (strcasecmp(restore_mode_str,"auto")==0) {
216                         restore_mode = UAC_AUTO_RESTORE;
217                 } else {
218                         LM_ERR("unsupported value '%s' for restore_mode\n",  restore_mode_str);
219                         goto error;
220                 }
221         }
222
223         if ( (rr_from_param.len==0 || rr_to_param.len==0) && restore_mode!=UAC_NO_RESTORE)
224         {
225                 LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n");
226                 goto error;
227         }
228
229         /* parse the auth AVP spesc, if any */
230         if ( auth_username_avp || auth_password_avp || auth_realm_avp) {
231                 if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) {
232                         LM_ERR("partial definition of auth AVP!");
233                         goto error;
234                 }
235                 if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0
236                                 || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0
237                                 || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0
238                    ) {
239                         goto error;
240                 }
241         } else {
242                 memset( &auth_realm_spec, 0, sizeof(pv_spec_t));
243                 memset( &auth_password_spec, 0, sizeof(pv_spec_t));
244                 memset( &auth_username_spec, 0, sizeof(pv_spec_t));
245         }
246
247         /* load the TM API - FIXME it should be loaded only
248          * if NO_RESTORE and AUTH */
249         if (load_tm_api(&uac_tmb)!=0) {
250                 LM_ERR("can't load TM API\n");
251                 goto error;
252         }
253
254         if (restore_mode!=UAC_NO_RESTORE) {
255                 /* load the RR API */
256                 if (load_rr_api(&uac_rrb)!=0) {
257                         LM_ERR("can't load RR API\n");
258                         goto error;
259                 }
260
261
262                 if(restore_from_avp.s) {
263
264                         if (pv_parse_spec(&restore_from_avp, &avp_spec)==0      || avp_spec.type!=PVT_AVP) {
265                                 LM_ERR("malformed or non AVP %.*s AVP definition\n", restore_from_avp.len, restore_from_avp.s);
266                                 return -1;
267                         }
268
269                         if(pv_get_avp_name(0, &avp_spec.pvp, &restore_from_avp_name, &restore_from_avp_type)!=0) {
270                                 LM_ERR("[%.*s]- invalid AVP definition\n", restore_from_avp.len, restore_from_avp.s);
271                                 return -1;
272                         }
273
274                         restore_from_avp_type |= AVP_VAL_STR;
275
276                 }
277
278                 if(restore_to_avp.s) {
279
280                         if (pv_parse_spec(&restore_to_avp, &avp_spec)==0        || avp_spec.type!=PVT_AVP) {
281                                 LM_ERR("malformed or non AVP %.*s AVP definition\n", restore_to_avp.len, restore_to_avp.s);
282                                 return -1;
283                         }
284
285                         if(pv_get_avp_name(0, &avp_spec.pvp, &restore_to_avp_name, &restore_to_avp_type)!=0) {
286                                 LM_ERR("[%.*s]- invalid AVP definition\n", restore_to_avp.len, restore_to_avp.s);
287                                 return -1;
288                         }
289
290                         restore_to_avp_type |= AVP_VAL_STR;
291
292                 }
293
294
295                 if (restore_mode==UAC_AUTO_RESTORE) {
296                         /* we need the append_fromtag on in RR */
297
298                         if (uac_restore_dlg==0) {
299                                 if (!uac_rrb.append_fromtag) {
300                                         LM_ERR("'append_fromtag' RR param is not enabled!"
301                                                         " - required by AUTO restore mode\n");
302                                         goto error;
303                                 }
304                         } else {
305                                 if (uac_init_dlg()!=0) {
306                                         LM_ERR("failed to find dialog API - is dialog module loaded?\n");
307                                         goto error;
308                                 }
309                         }
310
311                         /* get all requests doing loose route */
312                         if (uac_rrb.register_rrcb( rr_checker, 0)!=0) {
313                                 LM_ERR("failed to install RR callback\n");
314                                 goto error;
315                         }
316                 }
317         }
318
319         if(reg_db_url.s && reg_db_url.len>=0)
320         {
321                 kam_srand(17 * getpid() + time(0));
322                 if(!reg_contact_addr.s || reg_contact_addr.len<=0)
323                 {
324                         LM_ERR("contact address parameter not set\n");
325                         goto error;
326                 }
327                 if(reg_active_init(reg_active_param)<0) {
328                         LM_ERR("failed to init reg active mode\n");
329                         goto error;
330                 }
331                 if(reg_htable_size>14)
332                         reg_htable_size = 14;
333                 if(reg_htable_size<2)
334                         reg_htable_size = 2;
335
336                 reg_htable_size = 1<<reg_htable_size;
337                 if(uac_reg_init_rpc()!=0)
338                 {
339                         LM_ERR("failed to register RPC commands\n");
340                         goto error;
341                 }
342                 if(uac_reg_init_ht(reg_htable_size)<0)
343                 {
344                         LM_ERR("failed to init reg htable\n");
345                         goto error;
346                 }
347
348                 register_procs(1);
349                 /* add child to update local config framework structures */
350                 cfg_register_child(1);
351         }
352         init_from_replacer();
353
354         uac_req_init();
355
356         return 0;
357 error:
358         return -1;
359 }
360
361 static int child_init(int rank)
362 {
363         int pid;
364
365         kam_srand((11 + rank) * getpid() * 17 +  time(0));
366
367         if (rank!=PROC_MAIN)
368                 return 0;
369
370         if(!reg_db_url.s || reg_db_url.len<=0)
371                 return 0;
372
373         pid=fork_process(PROC_TIMER, "TIMER UAC REG", 1);
374         if (pid<0)
375         {
376                 LM_ERR("failed to register timer routine as process\n");
377                 return -1;
378         }
379         if (pid==0){
380                 /* child */
381                 /* initialize the config framework */
382                 if (cfg_child_init())
383                         return -1;
384
385                 kam_srand(getpid() * 17 +  time(0));
386                 uac_reg_load_db();
387                 LM_DBG("run initial uac registration routine\n");
388                 uac_reg_timer(0);
389                 for(;;){
390                         /* update the local config framework structures */
391                         cfg_update();
392
393                         sleep(reg_timer_interval);
394                         uac_reg_timer(get_ticks());
395                 }
396         }
397         /* parent */
398         return 0;
399 }
400
401 static void mod_destroy(void)
402 {
403         destroy_credentials();
404 }
405
406
407 /************************** wrapper functions ******************************/
408
409 static int ki_restore_from(struct sip_msg *msg)
410 {
411         /* safety checks - must be a request */
412         if (msg->first_line.type!=SIP_REQUEST) {
413                 LM_ERR("called for something not request\n");
414                 return -1;
415         }
416
417         return (restore_uri(msg,&rr_from_param,&restore_from_avp,1)==0)?1:-1;
418 }
419
420 static int w_restore_from(struct sip_msg *msg, char *p1, char *p2)
421 {
422         return ki_restore_from(msg);
423 }
424
425 int ki_replace_from(sip_msg_t *msg, str *pdsp, str *puri)
426 {
427         str *uri = NULL;
428         str *dsp = NULL;
429
430         dsp = pdsp;
431         uri = (puri && puri->len) ? puri : NULL;
432
433         if(parse_from_header(msg) < 0) {
434                 LM_ERR("failed to find/parse FROM hdr\n");
435                 return -1;
436         }
437
438         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", dsp, dsp ? dsp->len : 0, uri,
439                         uri ? uri->len : 0);
440
441         return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param,
442                                         &restore_from_avp, 1)==0)? 1 : -1;
443 }
444
445 static int ki_replace_from_uri(sip_msg_t* msg, str* puri)
446 {
447         return ki_replace_from(msg, NULL, puri);
448 }
449
450 int w_replace_from(struct sip_msg* msg, char* p1, char* p2)
451 {
452         str uri_s;
453         str dsp_s;
454         str *dsp = NULL;
455
456         if (p2==NULL) {
457                 p2 = p1;
458                 p1 = NULL;
459                 dsp = NULL;
460         }
461
462         /* p1 display , p2 uri */
463         if(p1 != NULL) {
464                 if(fixup_get_svalue(msg, (gparam_t *)p1, &dsp_s) < 0) {
465                         LM_ERR("cannot get the display name value\n");
466                         return -1;
467                 }
468                 dsp = &dsp_s;
469         }
470
471         /* compute the URI string; if empty string -> make it NULL */
472         if(fixup_get_svalue(msg, (gparam_t *)p2, &uri_s) < 0) {
473                 LM_ERR("cannot get the uri value\n");
474                 return -1;
475         }
476         return ki_replace_from(msg, dsp, &uri_s);
477 }
478
479 int replace_from_api(sip_msg_t *msg, str* pd, str* pu)
480 {
481         str *uri;
482         str *dsp;
483         if (parse_from_header(msg)<0 ) {
484                 LM_ERR("failed to find/parse FROM hdr\n");
485                 return -1;
486         }
487
488         uri = (pu!=NULL && pu->len>0)?pu:NULL;
489         dsp = (pd!=NULL && pd->len>0)?pd:NULL;
490
491         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", dsp, dsp?dsp->len:0,
492                         uri, uri?uri->len:0);
493
494         return replace_uri(msg, dsp, uri, msg->from, &rr_from_param, &restore_from_avp, 1);
495 }
496
497 static int ki_restore_to(struct sip_msg *msg)
498 {
499         /* safety checks - must be a request */
500         if (msg->first_line.type!=SIP_REQUEST) {
501                 LM_ERR("called for something not request\n");
502                 return -1;
503         }
504
505         return (restore_uri(msg,&rr_to_param,&restore_to_avp,0)==0)?1:-1;
506 }
507
508 static int w_restore_to(struct sip_msg *msg, char *p1, char *p2)
509 {
510         return ki_restore_to(msg);
511 }
512
513 static int ki_replace_to(sip_msg_t* msg, str* pdsp, str* puri)
514 {
515         str *uri = NULL;
516         str *dsp = NULL;
517
518         dsp = pdsp;
519         uri = (puri && puri->len) ? puri : NULL;
520
521         /* parse TO hdr */
522         if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) {
523                 LM_ERR("failed to parse TO hdr\n");
524                 return -1;
525         }
526
527         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n",
528                         dsp, dsp?dsp->len:0, uri, uri?uri->len:0);
529
530         return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param,
531                                 &restore_to_avp, 0)==0)?1:-1;
532 }
533
534 static int ki_replace_to_uri(sip_msg_t* msg, str* puri)
535 {
536         return ki_replace_to(msg, NULL, puri);
537 }
538
539 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2)
540 {
541         str uri_s;
542         str dsp_s;
543         str *dsp = NULL;
544
545         if (p2==NULL) {
546                 p2 = p1;
547                 p1 = NULL;
548                 dsp = NULL;
549         }
550
551         /* p1 display , p2 uri */
552         if(p1 != NULL) {
553                 if(fixup_get_svalue(msg, (gparam_t *)p1, &dsp_s) < 0) {
554                         LM_ERR("cannot get the display name value\n");
555                         return -1;
556                 }
557                 dsp = &dsp_s;
558         }
559
560         /* compute the URI string; if empty string -> make it NULL */
561         if(fixup_get_svalue(msg, (gparam_t *)p2, &uri_s) < 0) {
562                 LM_ERR("cannot get the uri value\n");
563                 return -1;
564         }
565         return ki_replace_to(msg, dsp, &uri_s);
566 }
567
568
569 int replace_to_api(sip_msg_t *msg, str* pd, str* pu)
570 {
571         str *uri;
572         str *dsp;
573         if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) {
574                 LM_ERR("failed to find/parse TO hdr\n");
575                 return -1;
576         }
577
578         uri = (pu!=NULL && pu->len>0)?pu:NULL;
579         dsp = (pd!=NULL && pd->len>0)?pd:NULL;
580
581         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", dsp, dsp?dsp->len:0,
582                         uri, uri?uri->len:0);
583
584         return replace_uri(msg, dsp, uri, msg->to, &rr_to_param, &restore_to_avp, 0);
585 }
586
587
588 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
589 {
590         return (uac_auth(msg)==0)?1:-1;
591 }
592
593 static int ki_uac_auth(struct sip_msg* msg)
594 {
595         return (uac_auth(msg)==0)?1:-1;
596 }
597
598 static int w_uac_reg_lookup(struct sip_msg* msg, char* src, char* dst)
599 {
600         pv_spec_t *dpv;
601         str sval;
602
603         if(fixup_get_svalue(msg, (gparam_t*)src, &sval)<0) {
604                 LM_ERR("cannot get the uuid parameter\n");
605                 return -1;
606         }
607
608         dpv = (pv_spec_t*)dst;
609
610         return uac_reg_lookup(msg, &sval, dpv, 0);
611 }
612
613 static int ki_uac_reg_lookup(sip_msg_t* msg, str* userid, str* sdst)
614 {
615         pv_spec_t *dpv = NULL;
616         dpv = pv_cache_get(sdst);
617         if(dpv==NULL) {
618                 LM_ERR("cannot get pv spec for [%.*s]\n", sdst->len, sdst->s);
619                 return -1;
620         }
621         return uac_reg_lookup(msg, userid, dpv, 0);
622 }
623
624 static int w_uac_reg_status(struct sip_msg* msg, char* src, char* p2)
625 {
626         str sval;
627
628         if(fixup_get_svalue(msg, (gparam_t*)src, &sval)<0) {
629                 LM_ERR("cannot get the uuid parameter\n");
630                 return -1;
631         }
632
633         return uac_reg_status(msg, &sval, 0);
634 }
635
636 static int ki_uac_reg_status(sip_msg_t *msg, str *sruuid)
637 {
638         return uac_reg_status(msg, sruuid, 0);
639 }
640
641 static int w_uac_reg_enable(struct sip_msg* msg, char* pfilter, char* pval)
642 {
643         str sfilter;
644         str sval;
645
646         if(fixup_get_svalue(msg, (gparam_t*)pfilter, &sfilter)<0) {
647                 LM_ERR("cannot get the filter parameter\n");
648                 return -1;
649         }
650         if(fixup_get_svalue(msg, (gparam_t*)pval, &sval)<0) {
651                 LM_ERR("cannot get the value parameter\n");
652                 return -1;
653         }
654         return uac_reg_enable(msg, &sfilter, &sval);
655 }
656
657 static int w_uac_reg_disable(struct sip_msg* msg, char* pfilter, char* pval)
658 {
659         str sfilter;
660         str sval;
661
662         if(fixup_get_svalue(msg, (gparam_t*)pfilter, &sfilter)<0) {
663                 LM_ERR("cannot get the filter parameter\n");
664                 return -1;
665         }
666         if(fixup_get_svalue(msg, (gparam_t*)pval, &sval)<0) {
667                 LM_ERR("cannot get the value parameter\n");
668                 return -1;
669         }
670         return uac_reg_disable(msg, &sfilter, &sval);
671 }
672
673 static int w_uac_reg_refresh(struct sip_msg* msg, char* pluuid, char* p2)
674 {
675         str sluuid;
676
677         if(fixup_get_svalue(msg, (gparam_t*)pluuid, &sluuid)<0) {
678                 LM_ERR("cannot get the local uuid parameter\n");
679                 return -1;
680         }
681         return uac_reg_refresh(msg, &sluuid);
682 }
683
684 static int w_uac_reg_request_to(struct sip_msg* msg, char* src, char* pmode)
685 {
686         str sval;
687         int imode;
688
689         if(fixup_get_svalue(msg, (gparam_t*)src, &sval)<0) {
690                 LM_ERR("cannot get the uuid parameter\n");
691                 return -1;
692         }
693         if(fixup_get_ivalue(msg, (gparam_t*)pmode, &imode)<0) {
694                 LM_ERR("cannot get the mode parameter\n");
695                 return -1;
696         }
697
698         if (imode > 1) {
699                 LM_ERR("invalid mode\n");
700                 return -1;
701         }
702
703         return uac_reg_request_to(msg, &sval, (unsigned int)imode);
704 }
705
706 static int ki_uac_reg_request_to(sip_msg_t *msg, str *userid, int imode)
707 {
708         if (imode > 1) {
709                 LM_ERR("invalid mode\n");
710                 return -1;
711         }
712
713         return uac_reg_request_to(msg, userid, (unsigned int)imode);
714 }
715
716 int bind_uac(uac_api_t *uacb)
717 {
718         if (uacb == NULL) {
719                 LM_WARN("bind_uac: Cannot load uac API into a NULL pointer\n");
720                 return -1;
721         }
722
723         memset(uacb, 0, sizeof(uac_api_t));
724         uacb->replace_from = replace_from_api;
725         uacb->replace_to = replace_to_api;
726         uacb->req_send = uac_req_send;
727         return 0;
728 }
729
730 /**
731  *
732  */
733 /* clang-format off */
734 static sr_kemi_t sr_kemi_uac_exports[] = {
735         { str_init("uac"), str_init("uac_auth"),
736                 SR_KEMIP_INT, ki_uac_auth,
737                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
738                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
739         },
740         { str_init("uac"), str_init("uac_req_send"),
741                 SR_KEMIP_INT, ki_uac_req_send,
742                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
743                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
744         },
745         { str_init("uac"), str_init("uac_replace_from_uri"),
746                 SR_KEMIP_INT, ki_replace_from_uri,
747                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
748                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
749         },
750         { str_init("uac"), str_init("uac_replace_from"),
751                 SR_KEMIP_INT, ki_replace_from,
752                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
753                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
754         },
755         { str_init("uac"), str_init("uac_restore_from"),
756                 SR_KEMIP_INT, ki_restore_from,
757                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
758                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
759         },
760         { str_init("uac"), str_init("uac_replace_to_uri"),
761                 SR_KEMIP_INT, ki_replace_to_uri,
762                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
763                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
764         },
765         { str_init("uac"), str_init("uac_replace_to"),
766                 SR_KEMIP_INT, ki_replace_to,
767                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
768                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
769         },
770         { str_init("uac"), str_init("uac_restore_to"),
771                 SR_KEMIP_INT, ki_restore_to,
772                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
773                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
774         },
775         { str_init("uac"), str_init("uac_reg_lookup"),
776                 SR_KEMIP_INT, ki_uac_reg_lookup,
777                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
778                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
779         },
780         { str_init("uac"), str_init("uac_reg_status"),
781                 SR_KEMIP_INT, ki_uac_reg_status,
782                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
783                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
784         },
785         { str_init("uac"), str_init("uac_reg_request_to"),
786                 SR_KEMIP_INT, ki_uac_reg_request_to,
787                 { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
788                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
789         },
790         { str_init("uac"), str_init("uac_reg_enable"),
791                 SR_KEMIP_INT, uac_reg_enable,
792                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
793                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
794         },
795         { str_init("uac"), str_init("uac_reg_disable"),
796                 SR_KEMIP_INT, uac_reg_disable,
797                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
798                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
799         },
800         { str_init("uac"), str_init("uac_reg_refresh"),
801                 SR_KEMIP_INT, uac_reg_refresh,
802                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
803                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
804         },
805
806         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
807 };
808 /* clang-format on */
809
810 /**
811  *
812  */
813 int mod_register(char *path, int *dlflags, void *p1, void *p2)
814 {
815         sr_kemi_modules_add(sr_kemi_uac_exports);
816         return 0;
817 }