obsolete/pa/presentity.c
fdeceea5
 /*
  * Presence Agent, presentity structure and related functions
  *
  * $Id$
  *
95072403
  * Copyright (C) 2001-2003 FhG Fokus
2e54789d
  * Copyright (C) 2004 Jamey Hicks
fdeceea5
  *
  * 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
  */
 
9470206e
 
 #include <stdio.h>
2e54789d
 #include <stdlib.h>
9470206e
 #include <string.h>
7a7f1a7b
 #include "../../lib/srdb2/db.h"
9470206e
 #include "../../dprint.h"
19ef0e8f
 #include "../../id.h"
fdeceea5
 #include "../../mem/shm_mem.h"
9470206e
 #include "../../ut.h"
1e406260
 #include "../../parser/parse_event.h"
fdeceea5
 #include "paerrno.h"
49447807
 #include "dlist.h"
fdeceea5
 #include "notify.h"
49447807
 #include "pdomain.h"
9470206e
 #include "presentity.h"
b37fbbd0
 #include "ptime.h"
04847d67
 #include "pa_mod.h"
541e1786
 #include "qsa_interface.h"
 #include <cds/logger.h>
5d58dfb2
 #include <cds/dbid.h>
f7372307
 #include "async_auth.h"
5d58dfb2
 #include "tuple.h"
 #include "pres_notes.h"
018409d0
 #include "extension_elements.h"
fdeceea5
 
932d4114
 extern int use_db;
 
f7372307
 int auth_rules_refresh_time = 300;
 
5d58dfb2
 /* ----- helper functions ----- */
932d4114
 
5d58dfb2
 int get_presentity_uid(str *uid_dst, struct sip_msg *m)
932d4114
 {
5d58dfb2
 	/* Independently on implementation of get_to_uid this function
 	 * gets UID from the message. It never uses dynamic allocation of
 	 * data (better to use static buffer instead due to speed)! */
 	return get_to_uid(uid_dst, m);
932d4114
 }
 
5d58dfb2
 void free_tuple_change_info_content(tuple_change_info_t *i)
 {
 	str_free_content(&i->user);
 	str_free_content(&i->contact);
 }
 
 int pres_uri2uid(str_t *uid_dst, const str_t *uri)
2393d0b6
 {
5d58dfb2
 	/* FIXME: convert uri to uid - used by internal subscriptions and fifo
 	 * commands - throw it out and use UUID only! */
 
 	struct sip_uri puri;
 	
 	str_clear(uid_dst);
2393d0b6
 	
5d58dfb2
 /*	if (db_lookup_user(uri, uid_dst) == 0) return 0; */
19ef0e8f
 	
5d58dfb2
 	/* else try the "hack" */
 	if (parse_uri(uri->s, uri->len, &puri) == -1) {
 		LOG(L_ERR, "get_from_uid: Error while parsing From URI\n");
2393d0b6
 		return -1;
 	}
 	
5d58dfb2
 	str_dup(uid_dst, &puri.user);
 	strlower(uid_dst);
 	return 0;
2393d0b6
 }
fdeceea5
 
5d58dfb2
 /* ----- presentity functions ----- */
 
 /* Create a new presentity but do not update database.
  * If pres_id not set it generates new one, but only if db_mode set. */
 static inline int new_presentity_no_wb(struct pdomain *pdomain, str* _uri, 
f7372307
 		str *uid, 
 		xcap_query_params_t *xcap_params,
5d58dfb2
 		str *pres_id,
f7372307
 		presentity_t** _p)
fdeceea5
 {
541e1786
 	presentity_t* presentity;
 	int size = 0;
5d58dfb2
 	dbid_t id;
 	int id_len = 0;
 	char *xcap_param_buffer;
 	
19ef0e8f
 	if ((!_uri) || (!_p) || (!uid)) {
541e1786
 		paerrno = PA_INTERNAL_ERROR;
f7372307
 		ERR("Invalid parameter value\n");
541e1786
 		return -1;
 	}
 
5d58dfb2
 	if (pres_id) size += pres_id->len;
 	else {
 		if (use_db) { /* do not generate IDs if not using DB */
 			generate_dbid(id);
 			id_len = dbid_strlen(id);
 			size += id_len;
 		}
 		else id_len = 0;
 	}
 
 	if (xcap_params) size += get_inline_xcap_buf_len(xcap_params);
 	size += sizeof(presentity_t) + _uri->len + uid->len;
2a385f88
 	presentity = (presentity_t*)mem_alloc(size);
acc29cc4
 	/* TRACE("allocating presentity: %d\n", size); */
541e1786
 	if (!presentity) {
 		paerrno = PA_NO_MEMORY;
f7372307
 		LOG(L_ERR, "No memory left: size=%d\n", size);
2e472c6b
 		*_p = NULL;
541e1786
 		return -1;
 	}
5d58dfb2
 
 	/* fill whole structure with zeros */
541e1786
 	memset(presentity, 0, sizeof(presentity_t));
 
284e5638
 	msg_queue_init(&presentity->mq);
 
5d58dfb2
 	presentity->data.uri.s = ((char*)presentity) + sizeof(presentity_t);	
 	str_cpy(&presentity->data.uri, _uri);
 	presentity->uuid.s = presentity->data.uri.s + presentity->data.uri.len;
 	str_cpy(&presentity->uuid, uid);
 	presentity->pres_id.s = presentity->uuid.s + presentity->uuid.len;
 	if (pres_id) str_cpy(&presentity->pres_id, pres_id);
 	else {
 		if (use_db) dbid_strcpy(&presentity->pres_id, id, id_len);
 		else presentity->pres_id.len = 0;
 	}
 	xcap_param_buffer = after_str_ptr(&presentity->pres_id);
 			
541e1786
 	presentity->pdomain = pdomain;
f7372307
 
5d58dfb2
 	if (pa_auth_params.type == auth_xcap) { 
 		/* store XCAP parameters for async XCAP queries and refreshing
 		 * (FIXME: rewrite - use table of a few of existing XCAP parameter
 		 * sets instead of always duplicating because it will be mostly 
 		 * the same!) */
 		if (dup_xcap_params_inline(&presentity->xcap_params, xcap_params, 
 					xcap_param_buffer) < 0) {
 			ERR("can't duplicate XCAP parameters\n");
 			shm_free(presentity);
 			*_p = NULL;
 			return -1;
 		}
f7372307
 	}
 	if (ask_auth_rules(presentity) < 0) {
5d58dfb2
 		/* try it from timer again if fails here */
f7372307
 		presentity->auth_rules_refresh_time = act_time;
 	}
 	else presentity->auth_rules_refresh_time = act_time + auth_rules_refresh_time;
 	
541e1786
 	*_p = presentity;
 
fe8d6762
 	/* add presentity into domain */
 	add_presentity(pdomain, *_p);
 
541e1786
 	return 0;
 }
fdeceea5
 
5d58dfb2
 static inline int db_add_presentity(presentity_t* presentity)
541e1786
 {
2e472c6b
 	db_key_t query_cols[6];
 	db_val_t query_vals[6];
541e1786
 	int n_query_cols = 0;
2e472c6b
 	int res;
 	str str_xcap_params;
541e1786
 	
6a611e22
 	query_cols[0] = col_uri;
541e1786
 	query_vals[0].type = DB_STR;
 	query_vals[0].nul = 0;
5d58dfb2
 	query_vals[0].val.str_val = presentity->data.uri;
541e1786
 	n_query_cols++;
 
6a611e22
 	query_cols[n_query_cols] = col_pdomain;
541e1786
 	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++;
19ef0e8f
 	
6a611e22
 	query_cols[n_query_cols] = col_uid;
19ef0e8f
 	query_vals[n_query_cols].type = DB_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = presentity->uuid;
 	n_query_cols++;
5d58dfb2
 	
6a611e22
 	query_cols[n_query_cols] = col_pres_id;
5d58dfb2
 	query_vals[n_query_cols].type = DB_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = presentity->pres_id;
 	n_query_cols++;
 	
2e472c6b
 	/*query_cols[n_query_cols] = "id_cntr";
5d58dfb2
 	query_vals[n_query_cols].type = DB_INT;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = presentity->id_cntr;
2e472c6b
 	n_query_cols++;*/
541e1786
 
2e472c6b
 	/* store XCAP parameters with presentity */
 	if (xcap_params2str(&str_xcap_params, &presentity->xcap_params) != 0) {
 		LOG(L_ERR, "Error while serializing xcap params\n");
 		return -1;
 	}
6a611e22
 	query_cols[n_query_cols] = col_xcap_params;
2e472c6b
 	query_vals[n_query_cols].type = DB_BLOB;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.blob_val = str_xcap_params;
 	n_query_cols++;
 	
 	res = 0;
 	
541e1786
 	if (pa_dbf.use_table(pa_db, presentity_table) < 0) {
f7372307
 		ERR("Error in use_table\n");
2e472c6b
 		res = -1;
541e1786
 	}
932d4114
 
5d58dfb2
 	/* insert new record into database */
2e472c6b
 	if (res == 0) {
 		if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) {
 			ERR("Error while inserting presentity into DB\n");
 			res = -1;
 		}
541e1786
 	}
2e472c6b
 	str_free_content(&str_xcap_params);
 	return res;
541e1786
 }
49447807
 
5d58dfb2
 /*
  * Create a new presentity
  */
 int new_presentity(struct pdomain *pdomain, str* _uri, str *uid, 
 		xcap_query_params_t *params, 
 		presentity_t** _p)
541e1786
 {
5d58dfb2
 	int res = 0;
49447807
 
5d58dfb2
 	res = new_presentity_no_wb(pdomain, _uri, uid, params, NULL, _p);
 	if (res != 0) return res;
541e1786
 	
5d58dfb2
 	if (use_db) {
 		if (db_add_presentity(*_p) != 0) { 
 			paerrno = PA_INTERNAL_ERROR;
 			free_presentity(*_p);
2e472c6b
 			*_p = NULL;
5d58dfb2
 			return -1;
 		}
541e1786
 	}
49447807
 
5d58dfb2
 	return res;
49447807
 }
 
5d58dfb2
 /* Removes all data for presentity (tuples, watchers, tuple notes, ...)
  * from database. It is possible due to that pres_id is unique identifier
  * common for all tables */
 int db_remove_presentity_data(presentity_t* presentity, const char *table)
541e1786
 {
6a611e22
 	db_key_t keys[] = { col_pres_id };
5d58dfb2
 	db_op_t ops[] = { OP_EQ };
 	db_val_t k_vals[] = { { DB_STR, 0, { .str_val = presentity->pres_id } } };
541e1786
 	
 	if (!use_db) return 0;
5d58dfb2
 	
 	if (pa_dbf.use_table(pa_db, table) < 0) {
 		ERR("Error in use_table\n");
541e1786
 		return -1;
 	}
 
5d58dfb2
 	if (pa_dbf.delete(pa_db, keys, ops, k_vals, 1) < 0) {
f7372307
 		LOG(L_ERR, "Error while querying presentity\n");
541e1786
 		return -1;
 	}
 	
 	return 0;
 }
 
5d58dfb2
 static inline int db_remove_presentity(presentity_t* presentity)
541e1786
 {
 	int res = 0;
 	
 	if (!use_db) return 0;
 	
5d58dfb2
 	res = db_remove_presentity_data(presentity, presentity_contact_table);
 	res = db_remove_presentity_data(presentity, tuple_notes_table) | res;
 	res = db_remove_presentity_data(presentity, watcherinfo_table) | res;
 	res = db_remove_presentity_data(presentity, presentity_notes_table) | res;
018409d0
 	res = db_remove_presentity_data(presentity, extension_elements_table) | res;
5d58dfb2
 	res = db_remove_presentity_data(presentity, presentity_table) | res;
541e1786
 	
 	return res;
6a50c251
 }
 
fe8d6762
 void release_presentity(presentity_t *_p)
 {
 	/* remove presentity from DB and free its memory */
 	if (_p) {
 		db_remove_presentity(_p);
 		free_presentity(_p);
 	}
 }
6a50c251
 
 void free_presentity(presentity_t* _p)
 {
5d58dfb2
 	watcher_t *w, *nw;
 	presence_tuple_t *tuple, *t;
541e1786
 	internal_pa_subscription_t *iw, *niw;
6a032821
 	pa_presence_note_t *n, *nn;
7d82594a
 	pa_extension_element_t *e, *ne;
6a50c251
 
fe8d6762
 	/* remove presentity from domain */
 	remove_presentity(_p->pdomain, _p);
 	
541e1786
 	/* watchers should be released already */
5d58dfb2
 	w = _p->first_watcher;
 	while (w) {
 		nw = w->next;
 		free_watcher(w);
 		w = nw;
6a50c251
 	}
 
5d58dfb2
 	w = _p->first_winfo_watcher;
 	while (w) {
 		nw = w->next;
 		free_watcher(w);
 		w = nw;
6a50c251
 	}
 	
5d58dfb2
 	t = get_first_tuple(_p);
 	while (t) {
 		tuple = t;
 		t = (presence_tuple_t*)t->data.next;
6a50c251
 		free_presence_tuple(tuple);
 	}
 
541e1786
 	iw = _p->first_qsa_subscription;
 	while (iw) {
 		niw = iw->next;
 		free_internal_subscription(iw);
 		iw = niw;
 	}
6a032821
 	
 	/* remove notes */
5d58dfb2
 	n = (pa_presence_note_t*)_p->data.first_note;
6a032821
 	while (n) {
5d58dfb2
 		nn = (pa_presence_note_t*)n->data.next;
6a032821
 		free_pres_note(n);
 		n = nn;
 	}
541e1786
 
7d82594a
 	/* remove extension_elements */
 	e = (pa_extension_element_t*)_p->data.first_unknown_element;
 	while (e) {
 		ne = (pa_extension_element_t*)e->data.next;
 		free_pa_extension_element(e);
 		e = ne;
 	}
 
55218f16
 	if (_p->authorization_info) {
 		free_pres_rules(_p->authorization_info);
 	}
284e5638
 
5d58dfb2
 	/* XCAP params are allocated "inline" -> no free needed - it will 
 	 * be freed with whole structure */
 	/* free_xcap_params_content(&_p->xcap_params); */
284e5638
 	msg_queue_destroy(&_p->mq);
2a385f88
 	mem_free(_p);
6a50c251
 }
 
5d58dfb2
 int pdomain_load_presentities(pdomain_t *pdomain)
541e1786
 {
 	if (!use_db) return 0;
 
5d58dfb2
 	db_key_t query_cols[1];
 	db_op_t  query_ops[1];
 	db_val_t query_vals[1];
541e1786
 
5d58dfb2
 	db_key_t result_cols[8];
 	db_res_t *res;
541e1786
 	int n_query_cols = 0;
5d58dfb2
 	int n_result_cols = 0;
 	int uri_col;
 	int presid_col;
 	int uid_col;
2e472c6b
 	int xcap_col;
5d58dfb2
 	int i;
 	presentity_t *presentity = NULL;
 	db_con_t* db = create_pa_db_connection(); /* must create its own connection (called before child init)! */
541e1786
 
5d58dfb2
 	if (!db) {
 		ERR("Can't load presentities - no DB connection\n");
541e1786
 		return -1;
 	}
 
5d58dfb2
 	act_time = time(NULL); /* needed for fetching auth rules, ... */
ffc31469
 
6a611e22
 	query_cols[n_query_cols] = col_pdomain;
5d58dfb2
 	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++;
541e1786
 
6a611e22
 	result_cols[uri_col = n_result_cols++] = col_uri;
 	result_cols[presid_col = n_result_cols++] = col_pres_id;
 	result_cols[uid_col = n_result_cols++] = col_uid;
 	result_cols[xcap_col = n_result_cols++] = col_xcap_params;
541e1786
 
5d58dfb2
 	if (pa_dbf.use_table(db, presentity_table) < 0) {
 		LOG(L_ERR, "pdomain_load_presentities: Error in use_table\n");
 		close_pa_db_connection(db);
541e1786
 		return -1;
 	}
 
5d58dfb2
 	if (pa_dbf.query (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");
 		close_pa_db_connection(db);
541e1786
 		return -1;
 	}
5d58dfb2
 	if (res) {
 		for (i = 0; i < res->n; i++) {
 			/* fill in tuple structure from database query result */
 			db_row_t *row = &res->rows[i];
 			db_val_t *row_vals = ROW_VALUES(row);
 			str uri = STR_NULL;
 			str pres_id = STR_NULL;
 			str uid = STR_NULL;
2e472c6b
 			str serialized_xcap_params = STR_NULL;
 			xcap_query_params_t xcap_params;
5d58dfb2
 			
 			if (!row_vals[uri_col].nul) {
 				uri.s = (char *)row_vals[uri_col].val.string_val;
 				uri.len = strlen(uri.s);
 			}
 			if (!row_vals[uid_col].nul) {
 				uid.s = (char *)row_vals[uid_col].val.string_val;
 				uid.len = strlen(uid.s);
 			}
 			if (!row_vals[presid_col].nul) {
 				pres_id.s = (char *)row_vals[presid_col].val.string_val;
 				pres_id.len = strlen(pres_id.s);
 			}
2e472c6b
 			if (!row_vals[xcap_col].nul) {
 				serialized_xcap_params.s = (char *)row_vals[xcap_col].val.string_val;
 				serialized_xcap_params.len = strlen(serialized_xcap_params.s);
 			}
541e1786
 
5d58dfb2
 			DBG("pdomain_load_presentities: pdomain=%.*s presentity uri=%.*s presid=%.*s\n",
 					pdomain->name->len, pdomain->name->s, uri.len, uri.s, 
 					pres_id.len, pres_id.s);
541e1786
 
2e472c6b
 			str2xcap_params(&xcap_params, &serialized_xcap_params);
 			new_presentity_no_wb(pdomain, &uri, &uid, &xcap_params, &pres_id, &presentity);
 			free_xcap_params_content(&xcap_params);
5d58dfb2
 		}
 		pa_dbf.free_result(db, res);
541e1786
 	}
 
 	for (presentity = pdomain->first; presentity; presentity = presentity->next) {
 		db_read_watcherinfo(presentity, db);
 		db_read_tuples(presentity, db);
6a032821
 		db_read_notes(presentity, db);
018409d0
 		db_read_extension_elements(presentity, db);
541e1786
 	}
 	
 	close_pa_db_connection(db);
 	return 0;
49447807
 }
19ef0e8f
 
f7372307
 int set_auth_rules(presentity_t *p, presence_rules_t *new_auth_rules)
d444bb05
 {
f7372307
 	watcher_t *w;
 	watcher_status_t s;
 	
 	/* ! call from locked region only ! */
 /*	INFO("setting auth rules\n"); */
 	
 	if (p->authorization_info) {
 		free_pres_rules(p->authorization_info); /* free old rules */
d444bb05
 	}
 
f7372307
 	p->authorization_info = new_auth_rules;
 	
 	/* reauthorize all watchers (but NOT winfo watchers - not needed
 	 * now because we have only "implicit" auth. rules for them) */
 	
5d58dfb2
 	w = p->first_watcher;
f7372307
 	while (w) {
 		s = authorize_watcher(p, w);
 		if (w->status != s) {
 			/* status has changed */
 			w->status = s;
 			w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
5d58dfb2
 			p->flags |= PFLAG_WATCHERINFO_CHANGED;
f7372307
 			/* NOTIFYs, terminating, ... wil be done in timer */
d444bb05
 		}
f7372307
 		w = w->next;
d444bb05
 	}
f7372307
 	
 	return 0;
d444bb05
 }