/*
* Presence Agent, presentity structure and related functions
*
* $Id: presentity.c,v 1.20.2.1 2005/06/06 16:27:32 andrei Exp $
*
* Copyright (C) 2001-2003 FhG Fokus
* Copyright (C) 2004 Jamey Hicks
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../db/db.h"
#include "../../dprint.h"
#include "../../mem/shm_mem.h"
#include "../../ut.h"
#include "../../parser/parse_event.h"
#include "paerrno.h"
#include "dlist.h"
#include "notify.h"
#include "pdomain.h"
#include "presentity.h"
#include "ptime.h"
#include "pa_mod.h"
#include "location.h"
extern int use_db;
extern char *presentity_table;
str pstate_name[PS_NSTATES] = {
{ "unknown", sizeof("unknown") - 1 },
{ "online", sizeof("online") - 1 },
{ "offline", sizeof("offline") - 1 },
{ "away", sizeof("away") - 1 },
{ "xaway", sizeof("xaway") - 1 },
{ "dnd", sizeof("dnd") - 1 },
{ "typing", sizeof("typing") - 1 },
};
int basic2status(str basic)
{
int i;
for ( i= 0; i < PS_NSTATES; i++ ) {
if (str_strcasecmp(&pstate_name[i], &basic) == 0) {
return i;
}
}
return 0;
}
str str_strdup(str string)
{
str new_string;
new_string.s = shm_malloc(string.len + 1);
new_string.len = string.len;
strncpy(new_string.s, string.s, string.len);
new_string.s[string.len] = 0;
return new_string;
}
/*
* Create a new presentity but do not update database
*/
int new_presentity_no_wb(struct pdomain *pdomain, str* _uri, presentity_t** _p)
{
presentity_t* presentity;
int size = 0;
if (!_uri || !_p) {
paerrno = PA_INTERNAL_ERROR;
LOG(L_ERR, "new_presentity(): Invalid parameter value\n");
return -1;
}
size = sizeof(presentity_t) + _uri->len + 1;
presentity = (presentity_t*)shm_malloc(size);
if (!presentity) {
paerrno = PA_NO_MEMORY;
LOG(L_ERR, "new_presentity(): No memory left: size=%d\n", size);
return -1;
}
memset(presentity, 0, sizeof(presentity_t));
presentity->uri.s = ((char*)presentity) + sizeof(presentity_t);
strncpy(presentity->uri.s, _uri->s, _uri->len);
presentity->uri.s[_uri->len] = 0;
presentity->uri.len = _uri->len;
presentity->pdomain = pdomain;
*_p = presentity;
LOG(L_ERR, "new_presentity_no_wb=%p for uri=%.*s\n",
presentity, presentity->uri.len, presentity->uri.s);
return 0;
}
/*
* Create a new presentity
*/
int new_presentity(struct pdomain *pdomain, str* _uri, presentity_t** _p)
{
presentity_t* presentity;
int size = 0;
if (!_uri || !_p) {
paerrno = PA_INTERNAL_ERROR;
LOG(L_ERR, "new_presentity(): Invalid parameter value\n");
return -1;
}
size = sizeof(presentity_t) + _uri->len + 1;
presentity = (presentity_t*)shm_malloc(size);
if (!presentity) {
paerrno = PA_NO_MEMORY;
LOG(L_ERR, "new_presentity(): No memory left: size=%d\n", size);
return -1;
}
memset(presentity, 0, sizeof(presentity_t));
presentity->uri.s = ((char*)presentity) + sizeof(presentity_t);
strncpy(presentity->uri.s, _uri->s, _uri->len);
presentity->uri.s[_uri->len] = 0;
presentity->uri.len = _uri->len;
presentity->pdomain = pdomain;
if (use_db) {
db_key_t query_cols[4];
db_op_t query_ops[4];
db_val_t query_vals[4];
db_key_t result_cols[4];
db_res_t *res;
int n_query_cols = 0;
int n_result_cols = 0;
int presid_col;
int presid = 0;
query_cols[0] = "uri";
query_ops[0] = OP_EQ;
query_vals[0].type = DB_STR;
query_vals[0].nul = 0;
query_vals[0].val.str_val = presentity->uri;
n_query_cols++;
query_cols[n_query_cols] = "pdomain";
query_ops[n_query_cols] = OP_EQ;
query_vals[n_query_cols].type = DB_STR;
query_vals[n_query_cols].nul = 0;
query_vals[n_query_cols].val.str_val = *presentity->pdomain->name;
n_query_cols++;
result_cols[presid_col = n_result_cols++] = "presid";
if (pa_dbf.use_table(pa_db, presentity_table) < 0) {
LOG(L_ERR, "new_presentity: Error in use_table\n");
return -1;
}
while (!presid) {
if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
result_cols, n_query_cols, n_result_cols, 0, &res) < 0) {
LOG(L_ERR, "new_presentity: Error while querying presentity\n");
return -1;
}
if (res && res->n > 0) {
/* fill in tuple structure from database query result */
db_row_t *row = &res->rows[0];
db_val_t *row_vals = ROW_VALUES(row);
presid = presentity->presid = row_vals[presid_col].val.int_val;
LOG(L_INFO, " presid=%d\n", presid);
} else {
/* insert new record into database */
LOG(L_INFO, "new_presentity: inserting %d cols into table\n", n_query_cols);
if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols)
< 0) {
LOG(L_ERR, "new_presentity: Error while inserting tuple\n");
return -1;
}
}
pa_dbf.free_result(pa_db, res);
}
}
*_p = presentity;
LOG(L_ERR, "new_presentity=%p for uri=%.*s\n",
presentity, presentity->uri.len, presentity->uri.s);
return 0;
}
/*
* Free all memory associated with a presentity
*/
void free_presentity(presentity_t* _p)
{
watcher_t* ptr;
presence_tuple_t *tuple;
return;
while(_p->watchers) {
ptr = _p->watchers;
_p->watchers = _p->watchers->next;
free_watcher(ptr);
}
while(_p->winfo_watchers) {
ptr = _p->winfo_watchers;
_p->winfo_watchers = _p->winfo_watchers->next;
free_watcher(ptr);
}
while(_p->tuples) {
tuple = _p->tuples;
_p->tuples = _p->tuples->next;
free_presence_tuple(tuple);
}
shm_free(_p);
}
/*
* Sync presentity to db if db is in use
*/
int db_update_presentity(presentity_t* _p)
{
if (use_db) {
presence_tuple_t *tuple;
db_key_t query_cols[22];
db_op_t query_ops[22];
db_val_t query_vals[22];
int n_selectors = 2;
int n_updates = 2;
int presid = _p->presid;
for (tuple = _p->tuples; tuple; tuple = tuple->next) {
n_selectors = 2;
n_updates = 2;
LOG(L_ERR, "db_update_presentity starting: use_place_table=%d presid=%d\n", use_place_table, presid);
query_cols[0] = "presid";
query_ops[0] = OP_EQ;
query_vals[0].type = DB_INT;
query_vals[0].nul = 0;
query_vals[0].val.int_val = presid;
query_cols[1] = "contact";
query_ops[1] = OP_EQ;
query_vals[1].type = DB_STR;
query_vals[1].nul = 0;
query_vals[1].val.str_val.s = tuple->contact.s;
query_vals[1].val.str_val.len = tuple->contact.len;
LOG(L_ERR, "db_update_presentity: tuple->contact=%.*s len=%d\n basic=%d expires=%ld priority=%f",
tuple->contact.len, tuple->contact.s, tuple->contact.len, tuple->state,
(long)tuple->expires, tuple->priority);
{
int n_query_cols = 2;
LOG(L_INFO, "db_update_presentity: cleaning contact from table\n");
if (pa_dbf.use_table(pa_db, presentity_contact_table) < 0) {
LOG(L_ERR, "db_update_presentity: Error in use_table\n");
return -1;
}
if (pa_dbf.delete(pa_db, query_cols, query_ops, query_vals,
n_query_cols) < 0) {
LOG(L_ERR, "db_update_presentity: Error while deleting tuple\n");
return -1;
}
if (tuple->state == PS_OFFLINE)
continue;
}
query_cols[n_updates] = "basic";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val.s = pstate_name[tuple->state].s;
query_vals[n_updates].val.str_val.len = strlen(pstate_name[tuple->state].s);
n_updates++;
query_cols[n_updates] = "tupleid";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val.s = tuple->id.s;
query_vals[n_updates].val.str_val.len = tuple->id.len;
n_updates++;
if (use_place_table) {
int placeid = 0;
LOG(L_ERR, "db_update_presentity: room=%.*s loc=%.*s\n",
tuple->location.room.len, tuple->location.room.s,
tuple->location.loc.len, tuple->location.loc.s);
if (tuple->location.room.len && tuple->location.room.s) {
location_lookup_placeid(&tuple->location.room, &placeid);
} else if (tuple->location.loc.len && tuple->location.loc.s) {
location_lookup_placeid(&tuple->location.loc, &placeid);
}
if (placeid) {
query_cols[n_updates] = "placeid";
query_vals[n_updates].type = DB_INT;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.int_val = placeid;
n_updates++;
}
} else {
if (tuple->location.loc.len && tuple->location.loc.s) {
query_cols[n_updates] = "location";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val = tuple->location.loc;
LOG(L_ERR, "db_update_presentity: tuple->location.loc=%s len=%d\n",
tuple->location.loc.s, tuple->location.loc.len);
n_updates++;
}
if (tuple->location.site.len && tuple->location.site.s) {
query_cols[n_updates] = "site";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val = tuple->location.site;
n_updates++;
}
if (tuple->location.floor.len && tuple->location.floor.s) {
query_cols[n_updates] = "floor";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val = tuple->location.floor;
n_updates++;
}
if (tuple->location.room.len && tuple->location.room.s) {
query_cols[n_updates] = "room";
query_vals[n_updates].type = DB_STR;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.str_val = tuple->location.room;
n_updates++;
}
}
if (tuple->location.x != 0) {
query_cols[n_updates] = "x";
query_vals[n_updates].type = DB_DOUBLE;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.double_val = tuple->location.x;
n_updates++;
}
if (tuple->location.y != 0) {
query_cols[n_updates] = "y";
query_vals[n_updates].type = DB_DOUBLE;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.double_val = tuple->location.y;
n_updates++;
}
if (tuple->location.radius != 0) {
query_cols[n_updates] = "radius";
query_vals[n_updates].type = DB_DOUBLE;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.double_val = tuple->location.radius;
n_updates++;
}
if (tuple->priority != 0.0) {
query_cols[n_updates] = "priority";
query_vals[n_updates].type = DB_DOUBLE;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.double_val = tuple->priority;
n_updates++;
}
if (tuple->expires != 0) {
query_cols[n_updates] = "expires";
query_vals[n_updates].type = DB_DATETIME;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.time_val = tuple->expires;
n_updates++;
}
if (tuple->prescaps != 0) {
query_cols[n_updates] = "prescaps";
query_vals[n_updates].type = DB_INT;
query_vals[n_updates].nul = 0;
query_vals[n_updates].val.int_val = tuple->prescaps;
n_updates++;
}
if (n_updates > (sizeof(query_cols)/sizeof(db_key_t)))
LOG(L_ERR, "too many update values. n_selectors=%d, n_updates=%d "
"dbf.update=%p\n",
n_selectors, n_updates, pa_dbf.update);
if (pa_dbf.use_table(pa_db, presentity_contact_table) < 0) {
LOG(L_ERR, "db_update_presentity: Error in use_table\n");
return -1;
}
if (pa_dbf.insert(pa_db, query_cols, query_vals, n_updates) < 0) {
LOG(L_ERR, "db_update_presentity: Error while updating database\n");
return -1;
}
}
}
return 0;
}
/*
* Create a new presence_tuple
*/
int new_presence_tuple(str* _contact, time_t expires, presentity_t *_p, presence_tuple_t ** _t)
{
presence_tuple_t* tuple;
int size = 0;
int r;
if (!_contact || !_t) {
paerrno = PA_INTERNAL_ERROR;
LOG(L_ERR, "new_presence_tuple(): Invalid parameter value\n");
return -1;
}
size = sizeof(presence_tuple_t) + _contact->len + 1;
tuple = (presence_tuple_t*)shm_malloc(size);
if (!tuple) {
paerrno = PA_NO_MEMORY;
LOG(L_ERR, "new_presence_tuple(): No memory left: size=%d\n", size);
return -1;
}
memset(tuple, 0, sizeof(presence_tuple_t));
tuple->state = PS_UNKNOWN;
tuple->contact.s = ((char*)tuple) + sizeof(presence_tuple_t);
tuple->status.s = tuple->status_buf;
strncpy(tuple->contact.s, _contact->s, _contact->len);
_contact->s[_contact->len] = 0;
tuple->contact.len = _contact->len;
tuple->location.loc.s = tuple->location.loc_buf;
tuple->location.site.s = tuple->location.site_buf;
tuple->location.floor.s = tuple->location.floor_buf;
tuple->location.room.s = tuple->location.room_buf;
tuple->location.packet_loss.s = tuple->location.packet_loss_buf;
tuple->id.s = tuple->id_buf;
tuple->expires = expires;
tuple->priority = default_priority;
r = rand();
tuple->id.len = sprintf(tuple->id.s, "tid%x", r);
*_t = tuple;
LOG(L_ERR, "new_tuple=%p for aor=%.*s contact=%.*s\n", tuple,
_p->uri.len, _p->uri.s,
tuple->contact.len, tuple->contact.s);
return 0;
}
/*
* Find a presence_tuple for contact _contact on presentity _p
*/
int find_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t)
{
presence_tuple_t *tuple;
if (!_contact || !_contact->len || !_p || !_t) {
paerrno = PA_INTERNAL_ERROR;
LOG(L_ERR, "find_presence_tuple(): Invalid parameter value\n");
return -1;
}
tuple = _p->tuples;
LOG(L_ERR, "find_presence_tuple: _p=%p _p->tuples=%p\n", _p, _p->tuples);
while (tuple) {
if (str_strcasecmp(&tuple->contact, _contact) == 0) {
*_t = tuple;
return 0;
}
tuple = tuple->next;
}
return 1;
}
void add_presence_tuple(presentity_t *_p, presence_tuple_t *_t)
{
presence_tuple_t *tuples = _p->tuples;
_p->tuples = _t;
_t->next = tuples;
if (tuples) {
tuples->prev = _t;
}
}
void remove_presence_tuple(presentity_t *_p, presence_tuple_t *_t)
{
presence_tuple_t *tuples = _p->tuples;
if (tuples == _t) {
_p->tuples = _t->next;
}
if (_t->prev) {
_t->prev->next = _t->next;
}
if (_t->next) {
_t->next->prev = _t->prev;
}
}
/*
* Free all memory associated with a presence_tuple
*/
void free_presence_tuple(presence_tuple_t * _t)
{
shm_free(_t);
}
/*
* Print a presentity
*/
void print_presentity(FILE* _f, presentity_t* _p)
{
watcher_t* ptr;
fprintf(_f, "--presentity_t---\n");
fprintf(_f, "uri: '%.*s'\n", _p->uri.len, ZSW(_p->uri.s));
if (_p->watchers) {
ptr = _p->watchers;
while(ptr) {
print_watcher(_f, ptr);
ptr = ptr->next;
}
}
if (_p->winfo_watchers) {
ptr = _p->winfo_watchers;
while(ptr) {
print_watcher(_f, ptr);
ptr = ptr->next;
}
}
fprintf(_f, "---/presentity_t---\n");
}
int timer_presentity(presentity_t* _p)
{
watcher_t* watcher, *t;
presence_tuple_t *tuple;
if (_p && _p->flags)
LOG(L_ERR, "timer_presentity: _p=%p %s flags=%x watchers=%p\n", _p, _p->uri.s, _p->flags, _p->watchers);
if (_p->flags & PFLAG_WATCHERINFO_CHANGED) {
watcher_t *w = _p->watchers;
while (w) {
if (w && w->flags)
LOG(L_ERR, "\t w=%p %s flags=%x\n", w, w->uri.s, w->flags);
if (w->flags & WFLAG_SUBSCRIPTION_CHANGED) {
if (send_notify(_p, w) < 0) {
LOG(L_ERR, "handle_subscription(): Error while sending notify\n");
/* FIXME: watcher and presentity should be test for removal here
* (and possibly in other error cases too
*/
}
w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED;
}
w = w->next;
}
notify_winfo_watchers(_p);
/* We remove it here because a notify needs to be send first */
// if (w->expires == 0) free_watcher(w);
// if (p->slot == 0) free_presentity(p);
}
if (_p->flags & (PFLAG_PRESENCE_CHANGED
|PFLAG_PRESENCE_LISTS_CHANGED
|PFLAG_XCAP_CHANGED
|PFLAG_LOCATION_CHANGED)) {
notify_watchers(_p);
}
tuple = _p->tuples;
while (tuple) {
presence_tuple_t *next_tuple = tuple->next;
if (tuple->expires < act_time) {
LOG(L_ERR, "Expiring tuple %.*s\n", tuple->contact.len, tuple->contact.s);
remove_presence_tuple(_p, tuple);
}
tuple = next_tuple;
}
watcher = _p->watchers;
if (0) print_presentity(stdout, _p);
while(watcher) {
if (watcher->expires <= act_time) {
LOG(L_ERR, "Removing watcher %.*s\n", watcher->uri.len, watcher->uri.s);
watcher->expires = 0;
send_notify(_p, watcher);
t = watcher;
watcher = watcher->next;
remove_watcher(_p, t);
free_watcher(t);
continue;
}
watcher = watcher->next;
}
watcher = _p->winfo_watchers;
while(watcher) {
if (watcher->expires <= act_time) {
LOG(L_ERR, "Removing watcher %.*s\n", watcher->uri.len, watcher->uri.s);
watcher->expires = 0;
send_notify(_p, watcher);
t = watcher;
watcher = watcher->next;
remove_winfo_watcher(_p, t);
free_watcher(t);
continue;
}
watcher = watcher->next;
}
return 0;
}
/*
* Add a new watcher to the list
*/
int add_watcher(presentity_t* _p, str* _uri, time_t _e, int event_package, doctype_t _a, dlg_t* _dlg,
str *_dn, struct watcher** _w)
{
if (new_watcher(_p, _uri, _e, event_package, _a, _dlg, _dn, _w) < 0) {
LOG(L_ERR, "add_watcher(): Error while creating new watcher structure\n");
return -1;
}
(*_w)->next = _p->watchers;
_p->watchers = *_w;
return 0;
}
/*
* Remove a watcher from the list
*/
int remove_watcher(presentity_t* _p, watcher_t* _w)
{
watcher_t* watcher, *prev;
watcher = _p->watchers;
prev = 0;
while(watcher) {
if (watcher == _w) {
if (prev) {
prev->next = watcher->next;
} else {
_p->watchers = watcher->next;
}
return 0;
}
prev = watcher;
watcher = watcher->next;
}
/* Not found */
DBG("remove_watcher(): Watcher not found in the list\n");
return 1;
}
/*
* Notify all watchers in the list
*/
int notify_watchers(presentity_t* _p)
{
struct watcher* watcher = _p->watchers;
while(watcher) {
send_notify(_p, watcher);
watcher = watcher->next;
}
/* clear the flags */
_p->flags &= ~(PFLAG_PRESENCE_CHANGED
|PFLAG_PRESENCE_LISTS_CHANGED
|PFLAG_XCAP_CHANGED
|PFLAG_LOCATION_CHANGED);
_p->flags &= ~(PFLAG_PRESENCE_LISTS_CHANGED | PFLAG_WATCHERINFO_CHANGED);
return 0;
}
/*
* Notify all winfo watchers in the list
*/
int notify_winfo_watchers(presentity_t* _p)
{
struct watcher* watcher;
watcher = _p->winfo_watchers;
if (watcher)
LOG(L_ERR, "notify_winfo_watchers: presentity=%.*s winfo_watchers=%p\n", _p->uri.len, _p->uri.s, watcher);
while(watcher) {
LOG(L_ERR, "notify_winfo_watchers: watcher=%.*s\n", watcher->uri.len, watcher->uri.s);
send_notify(_p, watcher);
watcher = watcher->next;
}
/* clear the watcherinfo changed flag */
_p->flags &= ~PFLAG_WATCHERINFO_CHANGED;
return 0;
}
/*
* Add a new watcher to the winfo_watcher list
*/
int add_winfo_watcher(presentity_t* _p, str* _uri, time_t _e, int event_package, doctype_t _a, dlg_t* _dlg,
str *_dn, struct watcher** _w)
{
if (new_watcher(_p, _uri, _e, event_package, _a, _dlg, _dn, _w) < 0) {
LOG(L_ERR, "add_winfo_watcher(): Error while creating new watcher structure\n");
return -1;
}
(*_w)->accept = DOC_WINFO;
(*_w)->next = _p->winfo_watchers;
_p->winfo_watchers = *_w;
return 0;
}
/*
* Remove a watcher from the list
*/
int remove_winfo_watcher(presentity_t* _p, watcher_t* _w)
{
watcher_t* watcher, *prev;
watcher = _p->winfo_watchers;
prev = 0;
while(watcher) {
if (watcher == _w) {
if (prev) {
prev->next = watcher->next;
} else {
_p->winfo_watchers = watcher->next;
}
return 0;
}
prev = watcher;
watcher = watcher->next;
}
/* Not found */
DBG("remove_winfo_watcher(): Watcher not found in the list\n");
return 1;
}
/*
* Find a given watcher in the list
*/
int find_watcher(struct presentity* _p, str* _uri, int _et, watcher_t** _w)
{
watcher_t* watcher;
/* first look for watchers */
watcher = _p->watchers;
if (_et != EVENT_PRESENCE_WINFO) {
while(watcher) {
if ((_uri->len == watcher->uri.len) &&
(!memcmp(_uri->s, watcher->uri.s, _uri->len)) &&
(watcher->event_package == _et)) {
*_w = watcher;
return 0;
}
watcher = watcher->next;
}
} else {
/* now look for winfo watchers */
watcher = _p->winfo_watchers;
while(watcher) {
if ((_uri->len == watcher->uri.len) &&
(!memcmp(_uri->s, watcher->uri.s, _uri->len)) &&
(watcher->event_package == _et)) {
*_w = watcher;
return 0;
}
watcher = watcher->next;
}
}
return 1;
}
resource_list_t *resource_list_append_unique(resource_list_t *list, str *uri)
{
resource_list_t *head = list;
resource_list_t *last = NULL;
fprintf(stderr, "resource_lists_append_unique: list=%p uri=%.*s\n", list, uri->len, uri->s);
while (list) {
if (str_strcasecmp(&list->uri, uri) == 0)
return head;
last = list;
list = list->next;
}
list = (resource_list_t *)shm_malloc(sizeof(resource_list_t) + uri->len + 1);
list->uri.len = uri->len;
list->uri.s = ((char*)list) + sizeof(resource_list_t);
strncpy(list->uri.s, uri->s, uri->len);
list->uri.s[uri->len] = 0;
if (last) {
list->prev = last;
last->next = list;
}
if (head) {
return head;
} else {
return list;
}
}
resource_list_t *resource_list_remove(resource_list_t *list, str *uri)
{
resource_list_t *head = list;
resource_list_t *last = NULL;
resource_list_t *next = NULL;
while (list) {
if (str_strcasecmp(&list->uri, uri) == 0)
goto remove;
last = list;
list = list->next;
}
return head;
remove:
next = list->next;
if (last)
last->next = next;
if (next)
next->prev = last;
shm_free(list);
if (head == list)
return next;
else
return head;
}
/*
* Create a new presentity but no watcher list
*/
int create_presentity_only(struct sip_msg* _m, struct pdomain* _d, str* _puri,
struct presentity** _p)
{
event_t *parsed_event;
int et = EVENT_PRESENCE;
if (_m && _m->event) {
parsed_event = (event_t *)_m->event->parsed;
et = parsed_event->parsed;
}
if (new_presentity(_d, _puri, _p) < 0) {
LOG(L_ERR, "create_presentity_only(): Error while creating presentity\n");
return -2;
}
add_presentity(_d, *_p);
return 0;
}
int pdomain_load_presentities(pdomain_t *pdomain)
{
if (use_db) {
db_key_t query_cols[1];
db_op_t query_ops[1];
db_val_t query_vals[1];
db_key_t result_cols[4];
db_res_t *res;
int n_query_cols = 0;
int n_result_cols = 0;
int uri_col;
int presid_col;
int i;
query_cols[n_query_cols] = "pdomain";
query_ops[n_query_cols] = OP_EQ;
query_vals[n_query_cols].type = DB_STR;
query_vals[n_query_cols].nul = 0;
query_vals[n_query_cols].val.str_val = *pdomain->name;
n_query_cols++;
result_cols[uri_col = n_result_cols++] = "uri";
result_cols[presid_col = n_result_cols++] = "presid";
if (pa_dbf.use_table(pa_db, presentity_table) < 0) {
LOG(L_ERR, "pdomain_load_presentities: Error in use_table\n");
return -1;
}
if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
result_cols, n_query_cols, n_result_cols, 0, &res) < 0) {
LOG(L_ERR, "pdomain_load_presentities: Error while querying presentity\n");
return -1;
}
if (res) {
for (i = 0; i < res->n; i++) {
presentity_t *presentity = NULL;
/* fill in tuple structure from database query result */
db_row_t *row = &res->rows[i];
db_val_t *row_vals = ROW_VALUES(row);
int presid = row_vals[presid_col].val.int_val;
str uri;
if (!row_vals[uri_col].nul) {
uri.s = (char*)row_vals[uri_col].val.string_val;
uri.len = strlen(uri.s);
}
LOG(L_INFO, "pdomain_load_presentities: pdomain=%.*s presentity uri=%.*s presid=%d\n",
pdomain->name->len, pdomain->name->s, uri.len, uri.s, presid);
new_presentity_no_wb(pdomain, &uri, &presentity);
if (presentity) {
add_presentity(pdomain, presentity);
presentity->presid = presid;
}
}
pa_dbf.free_result(pa_db, res);
}
{
presentity_t *presentity;
for (presentity = pdomain->first; presentity; presentity = presentity->next) {
db_read_watcherinfo(presentity);
}
}
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1