/*
* Presence Agent, location package handling
*
* $Id: location.c,v 1.7 2004/08/24 08:58:32 janakj Exp $
*
* Copyright (C) 2001-2003 FhG Fokus
* Copyright (C) 2003-2004 Hewlett-Packard Company
*
* 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 <string.h>
#include "../../fifo_server.h"
#include "../../str.h"
#include "../../dprint.h"
#include "../../mem/mem.h"
#include "../../parser/parse_uri.h"
#include "../../parser/parse_from.h"
#include "../../parser/parse_expires.h"
#include "../../parser/parse_event.h"
#include "../../db/db.h"
#include "../../dprint.h"
#include "../../mem/shm_mem.h"
#include "dlist.h"
#include "presentity.h"
#include "watcher.h"
#include "pstate.h"
#include "notify.h"
#include "paerrno.h"
#include "pdomain.h"
#include "pa_mod.h"
#include "ptime.h"
#include "reply.h"
#include "subscribe.h"
#include "publish.h"
#include "common.h"
#include "pa_mod.h"
#define CRLF "\r\n"
#define CRLF_L (sizeof(CRLF) - 1)
#define PUBLIC_ID "//IETF//DTD RFCxxxx PIDF 1.0//EN"
#define PUBLIC_ID_L (sizeof(PUBLIC_ID) - 1)
#define XML_VERSION "<?xml version=\"1.0\"?>"
#define XML_VERSION_L (sizeof(XML_VERSION) - 1)
#define LOCATIONINFO_STAG "<locationinfo xmlns=\"urn:hplabs:params:xml:ns:locationinfo\" version=\"0\" state=\"full\">"
#define LOCATIONINFO_STAG_L (sizeof(LOCATIONINFO_STAG) - 1)
#define LOCATIONINFO_ETAG "</locationinfo>"
#define LOCATIONINFO_ETAG_L (sizeof(LOCATIONINFO_ETAG) - 1)
#define USERLIST_START " <user-list resource=\""
#define USERLIST_START_L (sizeof(USERLIST_START) - 1)
#define USERLIST_ETAG " </user-list>"
#define USERLIST_ETAG_L (sizeof(USERLIST_ETAG) - 1)
#define USER_START "<user entity=\""
#define USER_START_L (sizeof(USER_START) - 1)
#define USER_END "\">"
#define USER_END_L (sizeof(USER_END) - 1)
#define USER_ETAG "</user>"
#define USER_ETAG_L (sizeof(USER_ETAG) - 1)
#define add_string(_s, _l) ((strs[n_strs].s = (_s)), (strs[n_strs].len = (_l)), (len += _l), n_strs++)
#define add_str(_s) (strs[n_strs].s = (_s.s), strs[n_strs].len = (_s.len), len += _s.len, n_strs++)
#define add_pstr(_s) (strs[n_strs].s = (_s->s), strs[n_strs].len = (_s->len), len += _s->len, n_strs++)
/*
* Add a user information
*/
int location_doc_add_user(str* _b, int _l, str *user_uri)
{
str strs[10];
int n_strs = 0;
int i;
int len = 0;
add_string(USER_START, USER_START_L);
add_pstr(user_uri);
add_string(USER_END, USER_END_L);
add_string(USER_ETAG, USER_ETAG_L);
if (_l < len) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "location_add_user(): Buffer too small\n");
return -1;
}
for (i = 0; i < n_strs; i++)
str_append(_b, strs[i].s, strs[i].len);
return 0;
}
/*
* Create start of location document
*/
int location_doc_start(str* _b, int _l)
{
str strs[10];
int n_strs = 0;
int i;
int len = 0;
if ((XML_VERSION_L +
CRLF_L
) > _l) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "start_pidf_doc(): Buffer too small\n");
return -1;
}
add_string(XML_VERSION, XML_VERSION_L);
add_string(CRLF, CRLF_L);
add_string(LOCATIONINFO_STAG, LOCATIONINFO_STAG_L);
add_string(CRLF, CRLF_L);
if (_l < len) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "location_add_resource(): Buffer too small\n");
return -1;
}
for (i = 0; i < n_strs; i++)
str_append(_b, strs[i].s, strs[i].len);
return 0;
}
/*
* Start a resource in a location document
*/
int location_doc_start_userlist(str* _b, int _l, str* _uri)
{
str strs[10];
int n_strs = 0;
int i;
int len = 0;
add_string(USERLIST_START, USERLIST_START_L);
add_string(CRLF, CRLF_L);
if (_l < len) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "location_add_resource(): Buffer too small\n");
return -1;
}
for (i = 0; i < n_strs; i++)
str_append(_b, strs[i].s, strs[i].len);
return 0;
}
/*
* End a userlist in a location document
*/
int location_doc_end_resource(str *_b, int _l)
{
str strs[10];
int n_strs = 0;
int i;
int len = 0;
add_string(USERLIST_ETAG, USERLIST_ETAG_L);
add_string(CRLF, CRLF_L);
if (_l < len) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "location_add_resource(): Buffer too small\n");
return -1;
}
for (i = 0; i < n_strs; i++)
str_append(_b, strs[i].s, strs[i].len);
return 0;
}
/*
* End a location document
*/
int location_doc_end(str* _b, int _l)
{
if (_l < (LOCATIONINFO_ETAG_L + CRLF_L)) {
paerrno = PA_SMALL_BUFFER;
LOG(L_ERR, "end_pidf_doc(): Buffer too small\n");
return -1;
}
str_append(_b, LOCATIONINFO_ETAG CRLF, LOCATIONINFO_ETAG_L + CRLF_L);
return 0;
}
int location_placeid_n_rows;
struct location_placeid_row {
str room_name;
int placeid;
} *location_placeid_table;
static int compare_location_placeid_rows(const void *v1, const void *v2)
{
const struct location_placeid_row *r1 = v1;
const struct location_placeid_row *r2 = v2;
return str_strcasecmp(&r1->room_name, &r2->room_name);
}
static int places_initialized = 0;
int pa_location_init(void)
{
if (use_db) {
db_key_t query_cols[2];
db_op_t query_ops[2];
db_val_t query_vals[2];
db_key_t result_cols[4];
db_res_t *res;
int n_query_cols = 0;
int n_result_cols = 0;
int room_col, placeid_col;
result_cols[room_col = n_result_cols++] = "room";
result_cols[placeid_col = n_result_cols++] = "placeid";
if (pa_dbf.use_table(pa_db, place_table) < 0) {
LOG(L_ERR, "pa_location_init: 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, "pa_location_init: Error while querying tuple\n");
return -1;
}
LOG(L_ERR, "pa_location_init: res=%p res->n=%d\n", res, res->n);
if (res && res->n > 0) {
int r;
location_placeid_n_rows = res->n;
location_placeid_table = shm_malloc(res->n * sizeof(struct location_placeid_row));
for (r = 0; r < res->n; r++) {
db_row_t *res_row = &res->rows[r];
db_val_t *row_vals = ROW_VALUES(res_row);
str room_name;
struct location_placeid_row *row =
&location_placeid_table[r];
char *s;
room_name.s = row_vals[room_col].val.str_val.s;
row->room_name.len = room_name.len = strlen(room_name.s);
s = shm_malloc(row->room_name.len + 1);
row->placeid = row_vals[placeid_col].val.int_val;
row->room_name.s = s;
row->room_name.len = room_name.len;
strncpy(row->room_name.s, room_name.s, room_name.len);
row->room_name.s[room_name.len] = 0;
LOG(L_ERR, " placeid=%04d (nul=%d) room=%s len=%d (nul=%d)\n",
row->placeid, row_vals[placeid_col].nul,
row->room_name.s, row->room_name.len,
row_vals[room_col].nul);
}
}
pa_dbf.free_result(pa_db, res);
if (use_bsearch)
qsort(location_placeid_table, location_placeid_n_rows,
sizeof(struct location_placeid_row),
compare_location_placeid_rows);
}
return 0;
}
int location_lookup_placeid(str *room_name, int *placeid)
{
int i;
LOG(L_ERR, "location_lookup_placeid: room_name=%.*s\n", room_name->len, room_name->s);
if (!places_initialized) {
pa_location_init();
places_initialized = 1;
}
if (!use_bsearch) {
for (i = 0; i < location_placeid_n_rows; i++) {
struct location_placeid_row *row = &location_placeid_table[i];
if (str_strcasecmp(room_name, &row->room_name) == 0) {
*placeid = row->placeid;
LOG(L_ERR, " placeid=%d\n", row->placeid);
return 1;
}
}
*placeid = 0;
return 0;
} else {
struct location_placeid_row *row =
bsearch(room_name,
location_placeid_table, location_placeid_n_rows,
sizeof(struct location_placeid_row),
compare_location_placeid_rows);
if (row) {
*placeid = row->placeid;
LOG(L_ERR, " placeid=%d (bsearch)\n", row->placeid);
return 1;
} else {
*placeid = 0;
return 0;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1