mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
6.1 KiB
340 lines
6.1 KiB
#include "reg_avps.h"
|
|
#include "dlist.h"
|
|
#include "ul_mod.h"
|
|
#include "../../ut.h"
|
|
#include "../../sr_module.h"
|
|
|
|
static avp_flags_t reg_avp_flag = 0;
|
|
|
|
/* ************************************************************** */
|
|
/* utility functions */
|
|
|
|
/* FIXME - ugly */
|
|
extern avp_t *create_avp (avp_flags_t flags, avp_name_t name, avp_value_t val);
|
|
|
|
|
|
void trace_avp(const char *prolog, avp_t *avp)
|
|
{
|
|
str *s;
|
|
|
|
s = get_avp_name(avp);
|
|
if (s) INFO("%s: \"%.*s\" (flags = %d)\n", prolog, s->len, s->s, avp->flags);
|
|
else INFO("%s: unnamed AVP (flags = %d)\n", prolog, avp->flags);
|
|
}
|
|
|
|
|
|
int use_reg_avps()
|
|
{
|
|
return (reg_avp_flag != 0);
|
|
}
|
|
|
|
|
|
/* ************************************************************** */
|
|
/* internal functions for storing/restoring AVPs into ucontact */
|
|
|
|
static inline avp_t *avp_dup(avp_t *avp)
|
|
{
|
|
avp_value_t val;
|
|
avp_name_t name;
|
|
str *s;
|
|
|
|
if (avp) {
|
|
get_avp_val(avp, &val);
|
|
if (avp->flags & AVP_NAME_STR) {
|
|
s = get_avp_name(avp);
|
|
if (s) name.s = *s;
|
|
else {
|
|
name.s.s = NULL;
|
|
name.s.len = 0;
|
|
}
|
|
}
|
|
else name.n = avp->id;
|
|
return create_avp(avp->flags, name, val);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void reg_destroy_avps(avp_t *avp)
|
|
{
|
|
avp_t *n;
|
|
|
|
while (avp) {
|
|
n = avp->next;
|
|
shm_free(avp); /* FIXME: really ?? */
|
|
avp = n;
|
|
}
|
|
}
|
|
|
|
static void remove_avps(avp_t *avp)
|
|
{
|
|
struct search_state ss;
|
|
avp_name_t name;
|
|
avp_t *a;
|
|
str *s;
|
|
|
|
if (avp->flags & AVP_NAME_STR) {
|
|
s = get_avp_name(avp);
|
|
if (s) name.s = *s;
|
|
else {
|
|
name.s.s = NULL;
|
|
name.s.len = 0;
|
|
}
|
|
}
|
|
else name.n = avp->id;
|
|
|
|
a = search_first_avp(avp->flags, name, 0, &ss);
|
|
while(a) {
|
|
destroy_avp(a);
|
|
a = search_next_avp(&ss, 0);
|
|
}
|
|
}
|
|
|
|
static int save_reg_avps_impl(struct ucontact *c)
|
|
{
|
|
int i;
|
|
struct usr_avp *avp, *dup;
|
|
avp_t *first, *last;
|
|
static unsigned short lists[] = {
|
|
AVP_CLASS_USER | AVP_TRACK_FROM,
|
|
AVP_CLASS_USER | AVP_TRACK_TO,
|
|
AVP_CLASS_URI | AVP_TRACK_FROM,
|
|
AVP_CLASS_URI | AVP_TRACK_TO,
|
|
0
|
|
};
|
|
|
|
/* destroy old AVPs */
|
|
/* if (c->avps) db_delete_reg_avps(c); */
|
|
reg_destroy_avps(c->avps);
|
|
|
|
last = NULL;
|
|
first = NULL;
|
|
|
|
for (i = 0; lists[i]; i++) {
|
|
for (avp = get_avp_list(lists[i]); avp; avp = avp->next) {
|
|
|
|
/* trace_avp("trying to save avp", avp); */
|
|
|
|
if ((avp->flags & reg_avp_flag) == 0) continue;
|
|
|
|
/* trace_avp("saving avp", avp); */
|
|
|
|
dup = avp_dup(avp);
|
|
if (dup) {
|
|
/* add AVP into list */
|
|
if (last) last->next = dup;
|
|
else first = dup;
|
|
last = dup;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
c->avps = first;
|
|
/* if (c->avps) db_save_reg_avps(c); */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int restore_reg_avps(struct ucontact *info)
|
|
{
|
|
avp_t *avp;
|
|
avp_value_t val;
|
|
avp_name_t name;
|
|
str *s;
|
|
|
|
/* remove all these AVPs ? */
|
|
avp = info->avps;
|
|
while (avp) {
|
|
remove_avps(avp);
|
|
avp = avp->next;
|
|
}
|
|
|
|
/* add stored AVPs */
|
|
avp = info->avps;
|
|
while (avp) {
|
|
get_avp_val(avp, &val);
|
|
if (avp->flags & AVP_NAME_STR) {
|
|
s = get_avp_name(avp);
|
|
if (s) name.s = *s;
|
|
else {
|
|
name.s.s = NULL;
|
|
name.s.len = 0;
|
|
}
|
|
}
|
|
else name.n = avp->id;
|
|
|
|
/* trace_avp("restoring avp", avp); */
|
|
|
|
/* modify flags here? */
|
|
add_avp(avp->flags, name, val);
|
|
|
|
avp = avp->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int delete_reg_avps_impl(struct ucontact *info)
|
|
{
|
|
/* db_delete_reg_avps(info); */
|
|
if (info->avps) reg_destroy_avps(info->avps);
|
|
info->avps = NULL;
|
|
return 0;
|
|
}
|
|
|
|
/* ************************************************************** */
|
|
|
|
int set_reg_avpflag_name(char *name)
|
|
{
|
|
reg_avp_flag = 0;
|
|
|
|
if (name) {
|
|
if (!(*name)) return 0; /* -> don't use reg AVPs when zero length */
|
|
|
|
reg_avp_flag = register_avpflag(name);
|
|
if (!reg_avp_flag) {
|
|
ERR("can't register AVP flag %s\n", name);
|
|
return -1;
|
|
}
|
|
} /* else not use reg AVPs */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Take AVPS from the current lists and store them in the contact
|
|
* structure as registration AVPs. Existing registration AVPs will
|
|
* be destroyed.
|
|
*/
|
|
int save_reg_avps(struct ucontact *contact)
|
|
{
|
|
/* no locking here! */
|
|
|
|
if (!use_reg_avps()) return 0;
|
|
|
|
/* INFO("saving registration AVP flags\n"); */
|
|
return save_reg_avps_impl(contact);
|
|
}
|
|
|
|
|
|
/*
|
|
* Delete registration AVPs from the contact
|
|
*/
|
|
int delete_reg_avps(struct ucontact* c)
|
|
{
|
|
/* no locking here! */
|
|
|
|
if (!use_reg_avps()) return 0;
|
|
|
|
/*INFO("removing registration AVP flags\n");*/
|
|
return delete_reg_avps_impl(c);
|
|
}
|
|
|
|
|
|
/*
|
|
* Take registration AVPs from the contact and copy
|
|
* them to the current AVP lists
|
|
*/
|
|
int load_reg_avps(struct ucontact *contact)
|
|
{
|
|
/* lock udomain here! */
|
|
|
|
if (!use_reg_avps()) return 0;
|
|
|
|
/* INFO("loading registration AVP flags\n"); */
|
|
return restore_reg_avps(contact);
|
|
}
|
|
|
|
|
|
int read_reg_avps_fixup(void** param, int param_no)
|
|
{
|
|
udomain_t* d;
|
|
|
|
switch (param_no) {
|
|
case 1:
|
|
if (register_udomain((char*)*param, &d) < 0) {
|
|
ERR("Error while registering domain\n");
|
|
return -1;
|
|
}
|
|
*param = (void*)d;
|
|
break;
|
|
case 2:
|
|
return fixup_var_str_2(param, param_no);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int read_reg_avps(struct sip_msg *m, char* _domain, char* fp)
|
|
{
|
|
urecord_t* r = NULL;
|
|
struct ucontact *contact = NULL;
|
|
udomain_t *d;
|
|
str uid;
|
|
|
|
if (!use_reg_avps()) return 1;
|
|
|
|
d = (udomain_t*)_domain;
|
|
if (get_str_fparam(&uid, m, (fparam_t*)fp) < 0) {
|
|
ERR("invalid parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
/* INFO("reading avps for uid=%.*s\n", uid.len, ZSW(uid.s)); */
|
|
|
|
lock_udomain(d);
|
|
|
|
if (get_urecord(d, &uid, &r) != 0) {
|
|
unlock_udomain(d);
|
|
WARN("urecord not found\n");
|
|
return -1;
|
|
}
|
|
|
|
if (get_ucontact(r, &m->new_uri, &contact) != 0) {
|
|
unlock_udomain(d);
|
|
WARN("ucontact not found\n");
|
|
return -1;
|
|
}
|
|
|
|
load_reg_avps(contact);
|
|
|
|
unlock_udomain(d);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int dup_reg_avps(struct ucontact *dst, struct ucontact *src)
|
|
{
|
|
struct usr_avp *avp, *dup;
|
|
avp_t *first, *last;
|
|
|
|
/* no locking here! TODO: do it in package memory !!! */
|
|
|
|
if (!use_reg_avps()) return 0; /* don't use reg avps */
|
|
|
|
/* destroy old AVPs */
|
|
/* if (dst->avps) db_delete_reg_avps(dst); */
|
|
reg_destroy_avps(dst->avps);
|
|
|
|
last = NULL;
|
|
first = NULL;
|
|
|
|
avp = src->avps;
|
|
while (avp) {
|
|
dup = avp_dup(avp);
|
|
if (dup) {
|
|
/* add AVP into list */
|
|
if (last) last->next = dup;
|
|
else first = dup;
|
|
last = dup;
|
|
}
|
|
avp = avp->next;
|
|
}
|
|
|
|
dst->avps = first;
|
|
/* if (dst->avps) db_save_reg_avps(dst); */
|
|
|
|
return 0;
|
|
}
|