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