src/modules/presence/notify.c
467feeb2
 /*
  * presence module- presence server implementation
  *
  * Copyright (C) 2006 Voice Sistem S.R.L.
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
467feeb2
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
467feeb2
  * 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
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
467feeb2
  * 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.
  *
ea2ce2da
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
467feeb2
  *
  */
 
e01b2508
 /*! \file
9b64b9f3
  * \brief Kamailio presence module :: Notification with SIP NOTIFY
ea2ce2da
  * \ingroup presence
e01b2508
  */
 
 
a5d04f23
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
f42f79bf
 #include <libxml/parser.h>
a5d04f23
 
cf83221d
 #include "../../core/trim.h"
 #include "../../core/ut.h"
 #include "../../core/globals.h"
 #include "../../core/str.h"
e1615a19
 #include "../../lib/srdb1/db.h"
 #include "../../lib/srdb1/db_val.h"
cf83221d
 #include "../../core/hashes.h"
 #include "../../core/socket_info.h"
eb38b3df
 #include "../../modules/tm/tm_load.h"
85de52fc
 #include "../pua/hash.h"
651016d6
 #include "presentity.h"
a5d04f23
 #include "presence.h"
 #include "notify.h"
 #include "utils_func.h"
cf83221d
 #include "../../core/receive.h"
467feeb2
 
49b2cc3a
 #define ALLOC_SIZE 3000
ab9399b0
 #define MAX_FORWARD 70
 
4f692b41
 int goto_on_notify_reply = -1;
a3088218
 
2ae18b74
 extern int pres_local_log_level;
aa4c37ab
 extern int pres_local_log_facility;
4f692b41
 extern subs_t *_pres_subs_last_sub;
fb9351aa
 extern int _pres_subs_mode;
2ae18b74
 
4f692b41
 c_back_param *shm_dup_cbparam(subs_t *);
 void free_cbparam(c_back_param *cb_param);
467feeb2
 
4f692b41
 void p_tm_callback(struct cell *t, int type, struct tmcb_params *ps);
a3dd1f8f
 int add_waiting_watchers(watcher_t *watchers, str pres_uri, str event);
 int add_watcher_list(subs_t *s, watcher_t *watchers);
4f692b41
 str *create_winfo_xml(watcher_t *watchers, char *version, str resource,
 		str event, int STATE_FLAG);
 void free_watcher_list(watcher_t *watchers);
467feeb2
 
e2cf6343
 str str_to_user_col = str_init("to_user");
 str str_username_col = str_init("username");
 str str_domain_col = str_init("domain");
 str str_body_col = str_init("body");
 str str_to_domain_col = str_init("to_domain");
63ab6b48
 str str_from_user_col = str_init("from_user");
 str str_from_domain_col = str_init("from_domain");
e2cf6343
 str str_watcher_username_col = str_init("watcher_username");
 str str_watcher_domain_col = str_init("watcher_domain");
 str str_event_id_col = str_init("event_id");
 str str_event_col = str_init("event");
 str str_etag_col = str_init("etag");
b7a5016c
 str str_ruid_col = str_init("ruid");
e2cf6343
 str str_from_tag_col = str_init("from_tag");
 str str_to_tag_col = str_init("to_tag");
 str str_callid_col = str_init("callid");
 str str_local_cseq_col = str_init("local_cseq");
 str str_remote_cseq_col = str_init("remote_cseq");
 str str_record_route_col = str_init("record_route");
 str str_contact_col = str_init("contact");
 str str_expires_col = str_init("expires");
 str str_status_col = str_init("status");
 str str_reason_col = str_init("reason");
 str str_socket_info_col = str_init("socket_info");
 str str_local_contact_col = str_init("local_contact");
 str str_version_col = str_init("version");
 str str_presentity_uri_col = str_init("presentity_uri");
 str str_inserted_time_col = str_init("inserted_time");
 str str_received_time_col = str_init("received_time");
 str str_id_col = str_init("id");
a6357f83
 str str_sender_col = str_init("sender");
6583dd78
 str str_updated_col = str_init("updated");
 str str_updated_winfo_col = str_init("updated_winfo");
9f92b33c
 str str_priority_col = str_init("priority");
a3088218
 str str_flags_col = str_init("flags");
 str str_user_agent_col = str_init("user_agent");
e2cf6343
 
4f692b41
 int subset = 0;
8485536f
 
4f692b41
 char *get_status_str(int status_flag)
85de52fc
 {
4f692b41
 	switch(status_flag) {
 		case ACTIVE_STATUS:
 			return "active";
 		case PENDING_STATUS:
 			return "pending";
 		case TERMINATED_STATUS:
 			return "terminated";
 		case WAITING_STATUS:
 			return "waiting";
85de52fc
 	}
 	return NULL;
 }
 
4f692b41
 void printf_subs(subs_t *subs)
8485536f
 {
 	LM_DBG("pres_uri: %.*s\n", subs->pres_uri.len, subs->pres_uri.s);
4f692b41
 	LM_DBG("watcher_user@watcher_domain: %.*s@%.*s\n", subs->watcher_user.len,
 			subs->watcher_user.s, subs->watcher_domain.len,
 			subs->watcher_domain.s);
 	LM_DBG("to_user@to_domain: %.*s@%.*s\n", subs->to_user.len, subs->to_user.s,
 			subs->to_domain.len, subs->to_domain.s);
 	LM_DBG("from_user@from_domain: %.*s@%.*s\n", subs->from_user.len,
 			subs->from_user.s, subs->from_domain.len, subs->from_domain.s);
 	LM_DBG("callid/from_tag/to_tag: %.*s/%.*s/%.*s\n", subs->callid.len,
 			subs->callid.s, subs->from_tag.len, subs->from_tag.s,
 			subs->to_tag.len, subs->to_tag.s);
 	LM_DBG("local_cseq/remote_cseq: %u/%u\n", subs->local_cseq,
 			subs->remote_cseq);
 	LM_DBG("local_contact/contact: %.*s/%.*s\n", subs->local_contact.len,
 			subs->local_contact.s, subs->contact.len, subs->contact.s);
 	LM_DBG("record_route: %.*s\n", subs->record_route.len,
 			subs->record_route.s);
 	LM_DBG("sockinfo_str: %.*s\n", subs->sockinfo_str.len,
 			subs->sockinfo_str.s);
ea2ce2da
 
8485536f
 	LM_DBG("event: %.*s\n", subs->event->name.len, subs->event->name.s);
 	LM_DBG("status: %s\n", get_status_str(subs->status));
 	LM_DBG("reason: %.*s\n", subs->reason.len, subs->reason.s);
 	LM_DBG("version: %u\n", subs->version);
 	LM_DBG("expires: %u\n", subs->expires);
 
4f692b41
 	LM_DBG("updated/updated_winfo: %d/%d\n", subs->updated,
 			subs->updated_winfo);
467feeb2
 }
 
4f692b41
 int build_str_hdr(subs_t *subs, int is_body, str *hdr)
467feeb2
 {
4f692b41
 	pres_ev_t *event = subs->event;
a3dd1f8f
 	str expires = {0, 0};
 	str status = {0, 0};
4f692b41
 	char *p;
2b30581a
 	str trans = {";transport=", 11};
467feeb2
 
cd1ff536
 	if(hdr == NULL) {
a3dd1f8f
 		LM_ERR("bad parameter\n");
49b2cc3a
 		return -1;
467feeb2
 	}
a3dd1f8f
 	expires.s = int2str(subs->expires, &expires.len);
ea2ce2da
 
4f692b41
 	status.s = get_status_str(subs->status);
cd1ff536
 	if(status.s == NULL) {
a3dd1f8f
 		LM_ERR("bad status %d\n", subs->status);
49b2cc3a
 		return -1;
a3dd1f8f
 	}
 	status.len = strlen(status.s);
467feeb2
 
4f692b41
 	hdr->len =
 			18 /*Max-Forwards:  + val*/ + CRLF_LEN
 			+ 7 /*Event: */ + subs->event->name.len
 			+ 4 /*;id=*/ + subs->event_id.len + CRLF_LEN
 			+ 10 /*Contact: <*/ + subs->local_contact.len
 			+ 1 /*>*/ + 15 /*";transport=xxxx"*/ + CRLF_LEN
 			+ 20 /*Subscription-State: */ + status.len
 			+ 10 /*reason/expires params*/
 			+ (subs->reason.len > expires.len ? subs->reason.len : expires.len)
 			+ CRLF_LEN
 			+ (is_body ? (14 /*Content-Type: */ + subs->event->content_type.len
 								 + CRLF_LEN)
 					   : 0)
 			+ 1;
 
 	hdr->s = (char *)pkg_malloc(hdr->len);
cd1ff536
 	if(hdr->s == NULL) {
 		LM_ERR("no more pkg memory\n");
ab9399b0
 		return -1;
a3dd1f8f
 	}
 
cd1ff536
 	p = hdr->s;
 	p += sprintf(p, "Max-Forwards: %d\r\n", MAX_FORWARD);
a3dd1f8f
 
4f692b41
 	p += sprintf(p, "Event: %.*s", event->name.len, event->name.s);
cd1ff536
 	if(subs->event_id.len && subs->event_id.s) {
 		p += sprintf(p, ";id=%.*s", subs->event_id.len, subs->event_id.s);
 	}
 	memcpy(p, CRLF, CRLF_LEN);
 	p += CRLF_LEN;
a3dd1f8f
 
4f692b41
 	p += sprintf(p, "Contact: <%.*s", subs->local_contact.len,
 			subs->local_contact.s);
 	if(subs->sockinfo_str.s != NULL
 			&& str_search(&subs->local_contact, &trans) == 0) {
a3dd1f8f
 		/* fix me */
 		switch(subs->sockinfo_str.s[0]) {
 			case 's':
 			case 'S':
cd1ff536
 				memcpy(p, ";transport=sctp", 15);
 				p += 15;
4f692b41
 				break;
a3dd1f8f
 			case 't':
 			case 'T':
 				switch(subs->sockinfo_str.s[1]) {
 					case 'c':
 					case 'C':
cd1ff536
 						memcpy(p, ";transport=tcp", 14);
 						p += 14;
4f692b41
 						break;
a3dd1f8f
 					case 'l':
 					case 'L':
cd1ff536
 						memcpy(p, ";transport=tls", 14);
 						p += 14;
4f692b41
 						break;
a3dd1f8f
 				}
4f692b41
 				break;
a3dd1f8f
 		}
85de52fc
 	}
4f692b41
 	*p = '>';
cd1ff536
 	p++;
 	memcpy(p, CRLF, CRLF_LEN);
 	p += CRLF_LEN;
 
 	p += sprintf(p, "Subscription-State: %.*s", status.len, status.s);
 
 	if(subs->status == TERMINATED_STATUS) {
9e2825a4
 		LM_DBG("state = terminated\n");
cd1ff536
 		p += sprintf(p, ";reason=%.*s", subs->reason.len, subs->reason.s);
 	} else {
 		p += sprintf(p, ";expires=%.*s", expires.len, expires.s);
a3dd1f8f
 	}
cd1ff536
 	memcpy(p, CRLF, CRLF_LEN);
 	p += CRLF_LEN;
 
 	if(is_body) {
4f692b41
 		p += sprintf(p, "Content-Type: %.*s\r\n", event->content_type.len,
cd1ff536
 				event->content_type.s);
e806dc85
 	}
ea2ce2da
 
cd1ff536
 	*p = '\0';
 	hdr->len = p - hdr->s;
49b2cc3a
 
 	return 0;
467feeb2
 }
 
4f692b41
 int get_wi_subs_db(subs_t *subs, watcher_t *watchers)
ea2ce2da
 {
a3dd1f8f
 	subs_t sb;
8485536f
 	db_key_t query_cols[3];
4f692b41
 	db_op_t query_ops[3];
8485536f
 	db_val_t query_vals[3];
 	db_key_t result_cols[5];
e1615a19
 	db1_res_t *result = NULL;
4f692b41
 	db_row_t *row = NULL;
a5d04f23
 	db_val_t *row_vals = NULL;
467feeb2
 	int n_result_cols = 0;
 	int n_query_cols = 0;
85de52fc
 	int i;
a29a2a81
 	int status_col, watcher_user_col, watcher_domain_col, callid_col;
467feeb2
 
e2cf6343
 	query_cols[n_query_cols] = &str_presentity_uri_col;
467feeb2
 	query_ops[n_query_cols] = OP_EQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
4f692b41
 	query_vals[n_query_cols].val.str_val = subs->pres_uri;
467feeb2
 	n_query_cols++;
 
e2cf6343
 	query_cols[n_query_cols] = &str_event_col;
467feeb2
 	query_ops[n_query_cols] = OP_EQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
85de52fc
 	query_vals[n_query_cols].val.str_val = subs->event->wipeer->name;
467feeb2
 	n_query_cols++;
 
8485536f
 	query_cols[n_query_cols] = &str_expires_col;
 	query_ops[n_query_cols] = OP_GT;
 	query_vals[n_query_cols].type = DB1_INT;
 	query_vals[n_query_cols].nul = 0;
fe0e0b89
 	query_vals[n_query_cols].val.int_val = (int)time(NULL) + pres_expires_offset;
8485536f
 	n_query_cols++;
 
4f692b41
 	result_cols[status_col = n_result_cols++] = &str_status_col;
 	result_cols[watcher_user_col = n_result_cols++] = &str_watcher_username_col;
 	result_cols[watcher_domain_col = n_result_cols++] = &str_watcher_domain_col;
 	result_cols[callid_col = n_result_cols++] = &str_callid_col;
e2cf6343
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
9e2825a4
 		LM_ERR("in use_table\n");
a5d04f23
 		goto error;
467feeb2
 	}
 
4f692b41
 	if(pa_dbf.query(pa_db, query_cols, query_ops, query_vals, result_cols,
 			   n_query_cols, n_result_cols, 0, &result)
 			< 0) {
9e2825a4
 		LM_ERR("querying active_watchers db table\n");
a5d04f23
 		goto error;
467feeb2
 	}
 
4f692b41
 	if(result == NULL) {
a5d04f23
 		goto error;
467feeb2
 	}
85de52fc
 
4f692b41
 	if(result->n <= 0) {
9e2825a4
 		LM_DBG("The query in db table for active subscription"
4f692b41
 			   " returned no result\n");
85de52fc
 		pa_dbf.free_result(pa_db, result);
 		return 0;
 	}
ea2ce2da
 
4f692b41
 	for(i = 0; i < result->n; i++) {
85de52fc
 		row = &result->rows[i];
 		row_vals = ROW_VALUES(row);
ea2ce2da
 
4f692b41
 		sb.watcher_user.s = (char *)row_vals[watcher_user_col].val.string_val;
 		sb.watcher_user.len = strlen(sb.watcher_user.s);
47ec7120
 
4f692b41
 		sb.watcher_domain.s =
 				(char *)row_vals[watcher_domain_col].val.string_val;
 		sb.watcher_domain.len = strlen(sb.watcher_domain.s);
85de52fc
 
4f692b41
 		sb.callid.s = (char *)row_vals[callid_col].val.string_val;
 		sb.callid.len = strlen(sb.callid.s);
47ec7120
 
4f692b41
 		sb.event = subs->event->wipeer;
 		sb.status = row_vals[status_col].val.int_val;
ea2ce2da
 
4f692b41
 		if(add_watcher_list(&sb, watchers) < 0)
a3dd1f8f
 			goto error;
85de52fc
 	}
ea2ce2da
 
85de52fc
 	pa_dbf.free_result(pa_db, result);
 	return 0;
467feeb2
 
85de52fc
 error:
 	if(result)
 		pa_dbf.free_result(pa_db, result);
 	return -1;
 }
467feeb2
 
4f692b41
 str *get_wi_notify_body(subs_t *subs, subs_t *watcher_subs)
85de52fc
 {
4f692b41
 	str *notify_body = NULL;
 	char *version_str;
a3dd1f8f
 	watcher_t *watchers = NULL;
85de52fc
 	int len = 0;
 	unsigned int hash_code;
4f692b41
 	subs_t *s = NULL;
616d83a4
 	int state = FULL_STATE_FLAG;
ae86ca36
 	unsigned int now = (int)time(NULL);
467feeb2
 
47952aa3
 	hash_code = 0;
85de52fc
 	version_str = int2str(subs->version, &len);
4f692b41
 	if(version_str == NULL) {
9e2825a4
 		LM_ERR("converting int to str\n ");
85de52fc
 		goto error;
 	}
 
4f692b41
 	watchers = (watcher_t *)pkg_malloc(sizeof(watcher_t));
 	if(watchers == NULL) {
9e2825a4
 		ERR_MEM(PKG_MEM_STR);
85de52fc
 	}
 	memset(watchers, 0, sizeof(watcher_t));
 
4f692b41
 	if(watcher_subs != NULL) {
 		if(add_watcher_list(watcher_subs, watchers) < 0)
85de52fc
 			goto error;
616d83a4
 		state = PARTIAL_STATE_FLAG;
 
85de52fc
 		goto done;
 	}
 
fe0e0b89
 	if(pres_subs_dbmode == DB_ONLY) {
4f692b41
 		if(get_wi_subs_db(subs, watchers) < 0) {
9e2825a4
 			LM_ERR("getting watchers from database\n");
85de52fc
 			goto error;
467feeb2
 		}
ae86ca36
 	} else {
4f692b41
 		hash_code = core_case_hash(
 				&subs->pres_uri, &subs->event->wipeer->name, shtable_size);
ae86ca36
 		lock_get(&subs_htable[hash_code].lock);
4f692b41
 		s = subs_htable[hash_code].entries;
 		while(s->next) {
 			s = s->next;
85de52fc
 
4f692b41
 			if(s->expires < now) {
ae86ca36
 				LM_DBG("expired record\n");
 				continue;
 			}
85de52fc
 
4f692b41
 			if(s->event == subs->event->wipeer
 					&& s->pres_uri.len == subs->pres_uri.len
 					&& presence_sip_uri_match(&s->pres_uri, &subs->pres_uri)
 							   == 0) {
 				if(add_watcher_list(s, watchers) < 0) {
ae86ca36
 					lock_release(&subs_htable[hash_code].lock);
 					goto error;
 				}
 			}
85de52fc
 		}
ae86ca36
 		lock_release(&subs_htable[hash_code].lock);
85de52fc
 
4f692b41
 		if(add_waiting_watchers(
 				   watchers, subs->pres_uri, subs->event->wipeer->name)
 				< 0) {
ae86ca36
 			LM_ERR("failed to add waiting watchers\n");
 			goto error;
467feeb2
 		}
 	}
a3dd1f8f
 
85de52fc
 done:
4f692b41
 	notify_body = create_winfo_xml(watchers, version_str, subs->pres_uri,
a3dd1f8f
 			subs->event->wipeer->name, state);
4f692b41
 	if(notify_body == NULL) {
9e2825a4
 		LM_ERR("in function create_winfo_xml\n");
85de52fc
 		goto error;
 	}
a3dd1f8f
 	free_watcher_list(watchers);
467feeb2
 	return notify_body;
a5d04f23
 
 error:
a3dd1f8f
 	free_watcher_list(watchers);
 	return NULL;
 }
 
4f692b41
 void free_watcher_list(watcher_t *watchers)
a3dd1f8f
 {
4f692b41
 	watcher_t *w;
 	while(watchers) {
 		w = watchers;
 		if(w->uri.s != NULL)
85de52fc
 			pkg_free(w->uri.s);
4f692b41
 		if(w->id.s != NULL)
85de52fc
 			pkg_free(w->id.s);
4f692b41
 		watchers = watchers->next;
85de52fc
 		pkg_free(w);
a5d04f23
 	}
8485536f
 
 	watchers = NULL;
a3dd1f8f
 }
a5d04f23
 
a3dd1f8f
 int add_watcher_list(subs_t *s, watcher_t *watchers)
 {
4f692b41
 	watcher_t *w;
a3dd1f8f
 
4f692b41
 	w = (watcher_t *)pkg_malloc(sizeof(watcher_t));
 	if(w == NULL) {
a3dd1f8f
 		LM_ERR("No more private memory\n");
 		return -1;
 	}
4f692b41
 	w->status = s->status;
 	if(uandd_to_uri(s->watcher_user, s->watcher_domain, &w->uri) < 0) {
a3dd1f8f
 		LM_ERR("failed to create uri\n");
 		goto error;
 	}
4f692b41
 	w->id.s = (char *)pkg_malloc(s->callid.len + 1);
 	if(w->id.s == NULL) {
a3dd1f8f
 		LM_ERR("no more memory\n");
 		goto error;
 	}
 	memcpy(w->id.s, s->callid.s, s->callid.len);
 	w->id.len = s->callid.len;
 	w->id.s[w->id.len] = '\0';
 
4f692b41
 	w->next = watchers->next;
 	watchers->next = w;
a3dd1f8f
 
 	return 0;
 
 error:
4f692b41
 	if(w) {
a3dd1f8f
 		if(w->uri.s)
 			pkg_free(w->uri.s);
 		pkg_free(w);
 	}
 	return -1;
467feeb2
 }
85de52fc
 
4f692b41
 str *build_empty_bla_body(str pres_uri)
a6357f83
 {
 	xmlDocPtr doc;
 	xmlNodePtr node;
 	xmlAttrPtr attr;
4f692b41
 	str *body = NULL;
 	char *text;
a6357f83
 	int len;
4f692b41
 	char *entity = NULL;
a6357f83
 
 	doc = xmlNewDoc(BAD_CAST "1.0");
4f692b41
 	if(doc == NULL) {
a6357f83
 		LM_ERR("failed to construct xml document\n");
 		return NULL;
 	}
 
 	node = xmlNewNode(NULL, BAD_CAST "dialog-info");
4f692b41
 	if(node == NULL) {
a6357f83
 		LM_ERR("failed to initialize node\n");
 		goto error;
 	}
 	xmlDocSetRootElement(doc, node);
 
4f692b41
 	attr = xmlNewProp(node, BAD_CAST "xmlns",
 			BAD_CAST "urn:ietf:params:xml:ns:dialog-info");
 	if(attr == NULL) {
a6357f83
 		LM_ERR("failed to initialize node attribute\n");
 		goto error;
 	}
 	attr = xmlNewProp(node, BAD_CAST "version", BAD_CAST "1");
4f692b41
 	if(attr == NULL) {
a6357f83
 		LM_ERR("failed to initialize node attribute\n");
 		goto error;
 	}
 
 	attr = xmlNewProp(node, BAD_CAST "state", BAD_CAST "full");
4f692b41
 	if(attr == NULL) {
a6357f83
 		LM_ERR("failed to initialize node attribute\n");
 		goto error;
 	}
 
4f692b41
 	entity = (char *)pkg_malloc(pres_uri.len + 1);
 	if(entity == NULL) {
a6357f83
 		LM_ERR("no more memory\n");
 		goto error;
 	}
 	memcpy(entity, pres_uri.s, pres_uri.len);
4f692b41
 	entity[pres_uri.len] = '\0';
a6357f83
 
 	attr = xmlNewProp(node, BAD_CAST "entity", BAD_CAST entity);
4f692b41
 	if(attr == NULL) {
a6357f83
 		LM_ERR("failed to initialize node attribute\n");
 		pkg_free(entity);
 		goto error;
 	}
ea2ce2da
 
4f692b41
 	body = (str *)pkg_malloc(sizeof(str));
 	if(body == NULL) {
a6357f83
 		LM_ERR("no more private memory");
 		pkg_free(entity);
 		goto error;
 	}
 
4f692b41
 	xmlDocDumpFormatMemory(doc, (xmlChar **)(void *)&text, &len, 1);
 	body->s = (char *)pkg_malloc(len);
 	if(body->s == NULL) {
a6357f83
 		LM_ERR("no more private memory");
 		pkg_free(body);
 		pkg_free(entity);
 		goto error;
 	}
 	memcpy(body->s, text, len);
4f692b41
 	body->len = len;
a6357f83
 
ea2ce2da
 
a6357f83
 	pkg_free(entity);
 	xmlFreeDoc(doc);
 	xmlFree(text);
 
 	return body;
 
 error:
 	xmlFreeDoc(doc);
 	return NULL;
 }
 
737d92bb
 str *ps_db_get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag,
 		str *contact)
467feeb2
 {
1dceaa24
 	db_key_t query_cols[4];
 	db_val_t query_vals[4];
 	db_op_t query_ops[4];
a29a2a81
 	db_key_t result_cols[3];
e1615a19
 	db1_res_t *result = NULL;
4f692b41
 	int body_col, etag_col = 0, sender_col;
 	str **body_array = NULL;
 	str *notify_body = NULL;
 	db_row_t *row = NULL;
467feeb2
 	db_val_t *row_vals;
 	int n_result_cols = 0;
 	int n_query_cols = 0;
4f692b41
 	int i, n = 0, len;
 	int build_off_n = -1;
467feeb2
 	str etags;
4f692b41
 	str *body;
 	int size = 0;
85de52fc
 	struct sip_uri uri;
 	unsigned int hash_code;
a6357f83
 	str sender;
8729aa8c
 	static str query_str;
85de52fc
 
4f692b41
 	if(parse_uri(pres_uri.s, pres_uri.len, &uri) < 0) {
9e2825a4
 		LM_ERR("while parsing uri\n");
85de52fc
 		return NULL;
 	}
ae86ca36
 
a3d6d80d
 	/* if in db_only mode, get the presentity information from database - skip htable search */
f2c65b4c
 	if(publ_cache_mode == PS_PCACHE_HYBRID) {
ae86ca36
 		/* search in hash table if any record exists */
4f692b41
 		hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
 		if(search_phtable(&pres_uri, event->evp->type, hash_code) == NULL) {
ae86ca36
 			LM_DBG("No record exists in hash_table\n");
85de52fc
 
ae86ca36
 			/* for pidf manipulation */
4f692b41
 			if(event->agg_nbody) {
 				notify_body =
 						event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
ae86ca36
 				if(notify_body)
 					goto done;
 			}
 			return NULL;
 		}
 	}
467feeb2
 
e2cf6343
 	query_cols[n_query_cols] = &str_domain_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
85de52fc
 	query_vals[n_query_cols].val.str_val = uri.host;
1dceaa24
 	query_ops[n_query_cols] = OP_EQ;
467feeb2
 	n_query_cols++;
 
e2cf6343
 	query_cols[n_query_cols] = &str_username_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
85de52fc
 	query_vals[n_query_cols].val.str_val = uri.user;
1dceaa24
 	query_ops[n_query_cols] = OP_EQ;
467feeb2
 	n_query_cols++;
 
e2cf6343
 	query_cols[n_query_cols] = &str_event_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
0caecc44
 	query_vals[n_query_cols].nul = 0;
4f692b41
 	query_vals[n_query_cols].val.str_val = event->name;
1dceaa24
 	query_ops[n_query_cols] = OP_EQ;
 	n_query_cols++;
 
4f692b41
 	if(pres_startup_mode == 1) {
24d71219
 		query_cols[n_query_cols] = &str_expires_col;
 		query_vals[n_query_cols].type = DB1_INT;
 		query_vals[n_query_cols].nul = 0;
4f692b41
 		query_vals[n_query_cols].val.int_val = (int)time(NULL);
24d71219
 		query_ops[n_query_cols] = OP_GT;
 		n_query_cols++;
 	}
0caecc44
 
4f692b41
 	result_cols[body_col = n_result_cols++] = &str_body_col;
 	result_cols[etag_col = n_result_cols++] = &str_etag_col;
 	result_cols[sender_col = n_result_cols++] = &str_sender_col;
ea2ce2da
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
9e2825a4
 		LM_ERR("in use_table\n");
467feeb2
 		return NULL;
 	}
 
4f692b41
 	if(pres_retrieve_order == 1) {
8c5432e5
 		query_str = pres_retrieve_order_by;
a95abdfe
 	} else {
 		query_str = str_received_time_col;
 	}
4f692b41
 	if(pres_startup_mode == 1) {
 		if(pa_dbf.query(pa_db, query_cols, query_ops, query_vals, result_cols,
 				   n_query_cols, n_result_cols, &query_str, &result)
 				< 0) {
 			LM_ERR("failed to query %.*s table\n", presentity_table.len,
 					presentity_table.s);
24d71219
 			if(result)
 				pa_dbf.free_result(pa_db, result);
 			return NULL;
 		}
 	} else {
4f692b41
 		if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,
 				   n_query_cols, n_result_cols, &query_str, &result)
 				< 0) {
 			LM_ERR("failed to query %.*s table\n", presentity_table.len,
 					presentity_table.s);
24d71219
 			if(result)
 				pa_dbf.free_result(pa_db, result);
 			return NULL;
 		}
467feeb2
 	}
ea2ce2da
 
4f692b41
 	if(result == NULL)
55cbbb0b
 		return NULL;
 
4f692b41
 	if(result->n <= 0) {
9e2825a4
 		LM_DBG("The query returned no result\n[username]= %.*s"
4f692b41
 			   "\t[domain]= %.*s\t[event]= %.*s\n",
 				uri.user.len, uri.user.s, uri.host.len, uri.host.s,
 				event->name.len, event->name.s);
ea2ce2da
 
467feeb2
 		pa_dbf.free_result(pa_db, result);
4f692b41
 		result = NULL;
a1776eca
 
4f692b41
 		if(event->agg_nbody) {
85de52fc
 			notify_body = event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
a1776eca
 			if(notify_body)
 				goto done;
ea2ce2da
 		}
467feeb2
 		return NULL;
4f692b41
 	} else {
 		n = result->n;
 		if(event->agg_nbody == NULL) {
9e2825a4
 			LM_DBG("Event does not require aggregation\n");
4f692b41
 			row = &result->rows[n - 1];
0caecc44
 			row_vals = ROW_VALUES(row);
ea2ce2da
 
a6357f83
 			/* if event BLA - check if sender is the same as contact */
 			/* if so, send an empty dialog info document */
4f692b41
 			if(EVENT_DIALOG_SLA(event->evp) && contact) {
 				sender.s = (char *)row_vals[sender_col].val.string_val;
 				if(sender.s == NULL || strlen(sender.s) == 0)
a6357f83
 					goto after_sender_check;
4f692b41
 				sender.len = strlen(sender.s);
ea2ce2da
 
4f692b41
 				if(sender.len == contact->len
 						&& presence_sip_uri_match(&sender, contact) == 0) {
 					notify_body = build_empty_bla_body(pres_uri);
a6357f83
 					pa_dbf.free_result(pa_db, result);
 					return notify_body;
 				}
 			}
 
4f692b41
 		after_sender_check:
 			if(row_vals[body_col].val.string_val == NULL) {
9e2825a4
 				LM_ERR("NULL notify body record\n");
0caecc44
 				goto error;
 			}
4f692b41
 			len = strlen(row_vals[body_col].val.string_val);
 			if(len == 0) {
9e2825a4
 				LM_ERR("Empty notify body record\n");
0caecc44
 				goto error;
 			}
4f692b41
 			notify_body = (str *)pkg_malloc(sizeof(str));
 			if(notify_body == NULL) {
ea2ce2da
 				ERR_MEM(PKG_MEM_STR);
0caecc44
 			}
 			memset(notify_body, 0, sizeof(str));
4f692b41
 			notify_body->s = (char *)pkg_malloc(len * sizeof(char));
 			if(notify_body->s == NULL) {
0caecc44
 				pkg_free(notify_body);
9e2825a4
 				ERR_MEM(PKG_MEM_STR);
0caecc44
 			}
47ec7120
 			memcpy(notify_body->s, row_vals[body_col].val.string_val, len);
4f692b41
 			notify_body->len = len;
a1776eca
 			pa_dbf.free_result(pa_db, result);
ea2ce2da
 
a1776eca
 			return notify_body;
0caecc44
 		}
ea2ce2da
 
9e2825a4
 		LM_DBG("Event requires aggregation\n");
ea2ce2da
 
4f692b41
 		body_array = (str **)pkg_malloc((n + 2) * sizeof(str *));
 		if(body_array == NULL) {
9e2825a4
 			ERR_MEM(PKG_MEM_STR);
467feeb2
 		}
4f692b41
 		memset(body_array, 0, (n + 2) * sizeof(str *));
467feeb2
 
4f692b41
 		if(etag != NULL) {
 			LM_DBG("searched etag = %.*s len= %d\n", etag->len, etag->s,
 					etag->len);
9e2825a4
 			LM_DBG("etag not NULL\n");
4f692b41
 			for(i = 0; i < n; i++) {
467feeb2
 				row = &result->rows[i];
 				row_vals = ROW_VALUES(row);
4f692b41
 				etags.s = (char *)row_vals[etag_col].val.string_val;
467feeb2
 				etags.len = strlen(etags.s);
 
9e2825a4
 				LM_DBG("etag = %.*s len= %d\n", etags.len, etags.s, etags.len);
4f692b41
 				if((etags.len == etag->len)
 						&& (strncmp(etags.s, etag->s, etags.len) == 0)) {
9e2825a4
 					LM_DBG("found etag\n");
4f692b41
 					build_off_n = i;
a1776eca
 				}
4f692b41
 				len = strlen((char *)row_vals[body_col].val.string_val);
 				if(len == 0) {
9e2825a4
 					LM_ERR("Empty notify body record\n");
a1776eca
 					goto error;
 				}
ea2ce2da
 
4f692b41
 				size = sizeof(str) + len * sizeof(char);
 				body = (str *)pkg_malloc(size);
 				if(body == NULL) {
9e2825a4
 					ERR_MEM(PKG_MEM_STR);
a1776eca
 				}
 				memset(body, 0, size);
4f692b41
 				size = sizeof(str);
 				body->s = (char *)body + size;
 				memcpy(body->s, (char *)row_vals[body_col].val.string_val, len);
 				body->len = len;
a1776eca
 
4f692b41
 				body_array[i] = body;
467feeb2
 			}
4f692b41
 		} else {
 			for(i = 0; i < n; i++) {
467feeb2
 				row = &result->rows[i];
 				row_vals = ROW_VALUES(row);
ea2ce2da
 
4f692b41
 				len = strlen((char *)row_vals[body_col].val.string_val);
 				if(len == 0) {
9e2825a4
 					LM_ERR("Empty notify body record\n");
a1776eca
 					goto error;
 				}
ea2ce2da
 
4f692b41
 				size = sizeof(str) + len * sizeof(char);
 				body = (str *)pkg_malloc(size);
 				if(body == NULL) {
9e2825a4
 					ERR_MEM(PKG_MEM_STR);
a1776eca
 				}
 				memset(body, 0, size);
4f692b41
 				size = sizeof(str);
 				body->s = (char *)body + size;
a1776eca
 				memcpy(body->s, row_vals[body_col].val.string_val, len);
4f692b41
 				body->len = len;
a1776eca
 
4f692b41
 				body_array[i] = body;
ea2ce2da
 			}
0caecc44
 		}
a1776eca
 		pa_dbf.free_result(pa_db, result);
4f692b41
 		result = NULL;
ea2ce2da
 
4f692b41
 		notify_body = event->agg_nbody(
 				&uri.user, &uri.host, body_array, n, build_off_n);
467feeb2
 	}
f42f79bf
 
ea2ce2da
 done:
4f692b41
 	if(body_array != NULL) {
 		for(i = 0; i < n; i++) {
a1776eca
 			if(body_array[i])
 				pkg_free(body_array[i]);
 		}
467feeb2
 		pkg_free(body_array);
a1776eca
 	}
467feeb2
 	return notify_body;
 
 error:
4f692b41
 	if(result != NULL)
467feeb2
 		pa_dbf.free_result(pa_db, result);
a5d04f23
 
4f692b41
 	if(body_array != NULL) {
 		for(i = 0; i < n; i++) {
a1776eca
 			if(body_array[i])
 				pkg_free(body_array[i]);
 			else
 				break;
 		}
ea2ce2da
 
467feeb2
 		pkg_free(body_array);
a1776eca
 	}
467feeb2
 	return NULL;
 }
 
737d92bb
 str *ps_cache_get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag,
 		str *contact)
 {
 	sip_uri_t uri;
 	ps_presentity_t ptm;
 	ps_presentity_t *pti;
 	ps_presentity_t *ptlist = NULL;
 	int n = 0;
 	int i = 0;
 	str **body_array = NULL;
 	str *notify_body = NULL;
 	str *body;
 	int size = 0;
 	int build_off_n = -1;
 
 	if(parse_uri(pres_uri.s, pres_uri.len, &uri) < 0) {
 		LM_ERR("while parsing uri\n");
 		return NULL;
 	}
 	memset(&ptm, 0, sizeof(ps_presentity_t));
 
 	ptm.user = uri.user;
 	ptm.domain = uri.host;
 	ptm.event = event->name;
 	if(pres_startup_mode == 1) {
 		ptm.expires = (int)time(NULL);
 	}
 
74f50796
 	ptlist = ps_ptable_search(&ptm, 1, pres_retrieve_order);
737d92bb
 
 	if(ptlist == NULL) {
 		LM_DBG("the query returned no result\n[username]= %.*s"
 			   "\t[domain]= %.*s\t[event]= %.*s\n",
 				uri.user.len, uri.user.s, uri.host.len, uri.host.s,
 				event->name.len, event->name.s);
 
 		if(event->agg_nbody) {
 			notify_body = event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
 			if(notify_body) {
 				goto done;
 			}
 		}
 		return NULL;
 	}
 
 	if(event->agg_nbody == NULL) {
 		LM_DBG("event does not require aggregation\n");
 		pti = ptlist;
 		while(pti->next) {
 			pti = pti->next;
 		}
 
 		/* if event BLA - check if sender is the same as contact */
 		/* if so, send an empty dialog info document */
 		if(EVENT_DIALOG_SLA(event->evp) && contact) {
 			if(pti->sender.s == NULL || pti->sender.len <= 0) {
 				LM_DBG("no sender address\n");
 				goto after_sender_check;
 			}
 
 			if(pti->sender.len == contact->len
 					&& presence_sip_uri_match(&pti->sender, contact) == 0) {
 				notify_body = build_empty_bla_body(pres_uri);
 				ps_presentity_list_free(ptlist, 1);
 				return notify_body;
 			}
 		}
 
 	after_sender_check:
 		if(pti->body.s == NULL || pti->body.len <= 0) {
 			LM_ERR("NULL notify body record\n");
 			goto error;
 		}
 
 		notify_body = (str *)pkg_malloc(sizeof(str));
 		if(notify_body == NULL) {
 			ERR_MEM(PKG_MEM_STR);
 		}
 		memset(notify_body, 0, sizeof(str));
 		notify_body->s = (char *)pkg_malloc((pti->body.len+1) * sizeof(char));
 		if(notify_body->s == NULL) {
 			pkg_free(notify_body);
 			ERR_MEM(PKG_MEM_STR);
 		}
 		memcpy(notify_body->s, pti->body.s, pti->body.len);
 		notify_body->len = pti->body.len;
 		ps_presentity_list_free(ptlist, 1);
 
 		return notify_body;
 	}
 
 	LM_DBG("event requires aggregation\n");
 
 	n = 0;
 	pti = ptlist;
 	while(pti) {
 		n++;
 		pti = pti->next;
 	}
 	body_array = (str **)pkg_malloc((n + 2) * sizeof(str *));
 	if(body_array == NULL) {
 		ERR_MEM(PKG_MEM_STR);
 	}
 	memset(body_array, 0, (n + 2) * sizeof(str *));
 
 	if(etag != NULL) {
 		LM_DBG("searched etag = %.*s len= %d\n", etag->len, etag->s,
 				etag->len);
 		LM_DBG("etag not NULL\n");
 		pti = ptlist;
 		i = 0;
 		while(pti) {
 			LM_DBG("etag = %.*s len= %d\n", pti->etag.len, pti->etag.s,
 					pti->etag.len);
 			if((pti->etag.len == etag->len)
 					&& (strncmp(pti->etag.s, etag->s, pti->etag.len) == 0)) {
 				LM_DBG("found etag\n");
 				build_off_n = i;
 			}
 			if(pti->body.s == NULL || pti->body.len <= 0) {
 				LM_ERR("Empty notify body record\n");
 				goto error;
 			}
 
 			size = sizeof(str) + (pti->body.len +1) * sizeof(char);
 			body = (str *)pkg_malloc(size);
 			if(body == NULL) {
 				ERR_MEM(PKG_MEM_STR);
 			}
 			memset(body, 0, size);
 			size = sizeof(str);
 			body->s = (char *)body + size;
 			memcpy(body->s, pti->body.s, pti->body.len);
 			body->len = pti->body.len;
 
 			body_array[i] = body;
 			i++;
 			pti = pti->next;
 		}
 	} else {
 		pti = ptlist;
 		i = 0;
 		while(pti) {
 			if(pti->body.s == NULL || pti->body.len <= 0) {
 				LM_ERR("Empty notify body record\n");
 				goto error;
 			}
 
 			size = sizeof(str) + (pti->body.len+1) * sizeof(char);
 			body = (str *)pkg_malloc(size);
 			if(body == NULL) {
 				ERR_MEM(PKG_MEM_STR);
 			}
 			memset(body, 0, size);
 			size = sizeof(str);
 			body->s = (char *)body + size;
 			memcpy(body->s, pti->body.s, pti->body.len);
 			body->len = pti->body.len;
 
 			body_array[i] = body;
 			i++;
 			pti = pti->next;
 		}
 	}
 
 	ps_presentity_list_free(ptlist, 1);
 
 	notify_body = event->agg_nbody(
 			&uri.user, &uri.host, body_array, n, build_off_n);
 
 done:
 	if(body_array != NULL) {
 		for(i = 0; i < n; i++) {
 			if(body_array[i]) {
 				pkg_free(body_array[i]);
 			}
 		}
 		pkg_free(body_array);
 	}
 	return notify_body;
 
 error:
 	if(ptlist != NULL) {
 		ps_presentity_list_free(ptlist, 1);
 	}
 
 	if(body_array != NULL) {
 		for(i = 0; i < n; i++) {
 			if(body_array[i])
 				pkg_free(body_array[i]);
 			else
 				break;
 		}
 
 		pkg_free(body_array);
 	}
 	return NULL;
 }
 
 str *get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag, str *contact)
 {
 	if(publ_cache_mode == PS_PCACHE_RECORD) {
 		return ps_cache_get_p_notify_body(pres_uri, event, etag, contact);
 	} else {
 		return ps_db_get_p_notify_body(pres_uri, event, etag, contact);
 	}
 }
 
bd598ce9
 void free_notify_body(str *body, pres_ev_t *ev)
 {
4f692b41
 	if(body != NULL) {
 		if(body->s != NULL) {
 			if(ev->type & WINFO_TYPE)
bd598ce9
 				xmlFree(body->s);
4f692b41
 			else if(ev->agg_nbody == NULL && ev->apply_auth_nbody == NULL)
bd598ce9
 				pkg_free(body->s);
 			else
 				ev->free_body(body->s);
 		}
 		pkg_free(body);
 	}
 }
 
57d3284f
 static int ps_free_tm_dlg(dlg_t *td)
467feeb2
 {
4f692b41
 	if(td) {
85de52fc
 		if(td->loc_uri.s)
 			pkg_free(td->loc_uri.s);
 		if(td->rem_uri.s)
 			pkg_free(td->rem_uri.s);
 
467feeb2
 		if(td->route_set)
 			free_rr(&td->route_set);
 		pkg_free(td);
 	}
 	return 0;
 }
 
4f692b41
 dlg_t *ps_build_dlg_t(subs_t *subs)
467feeb2
 {
4f692b41
 	dlg_t *td = NULL;
467feeb2
 	int found_contact = 1;
 
4f692b41
 	td = (dlg_t *)pkg_malloc(sizeof(dlg_t));
 	if(td == NULL) {
9e2825a4
 		ERR_MEM(PKG_MEM_STR);
467feeb2
 	}
 	memset(td, 0, sizeof(dlg_t));
 
6afdbf4a
 	td->loc_seq.value = subs->local_cseq;
467feeb2
 	td->loc_seq.is_set = 1;
 
 	td->id.call_id = subs->callid;
 	td->id.rem_tag = subs->from_tag;
4f692b41
 	td->id.loc_tag = subs->to_tag;
ea2ce2da
 
85de52fc
 	uandd_to_uri(subs->to_user, subs->to_domain, &td->loc_uri);
4f692b41
 	if(td->loc_uri.s == NULL) {
9e2825a4
 		LM_ERR("while creating uri\n");
85de52fc
 		goto error;
 	}
467feeb2
 
4f692b41
 	if(subs->contact.len == 0 || subs->contact.s == NULL) {
467feeb2
 		found_contact = 0;
4f692b41
 	} else {
 		LM_DBG("CONTACT = %.*s\n", subs->contact.len, subs->contact.s);
467feeb2
 		td->rem_target = subs->contact;
 	}
 
85de52fc
 	uandd_to_uri(subs->from_user, subs->from_domain, &td->rem_uri);
4f692b41
 	if(td->rem_uri.s == NULL) {
9e2825a4
 		LM_ERR("while creating uri\n");
f49f7b35
 		goto error;
467feeb2
 	}
ea2ce2da
 
4f692b41
 	if(found_contact == 0) {
85de52fc
 		td->rem_target = td->rem_uri;
467feeb2
 	}
4f692b41
 	if(subs->record_route.s && subs->record_route.len) {
 		if(parse_rr_body(
 				   subs->record_route.s, subs->record_route.len, &td->route_set)
 				< 0) {
9e2825a4
 			LM_ERR("in function parse_rr_body\n");
6059779b
 			goto error;
 		}
ea2ce2da
 	}
4f692b41
 	td->state = DLG_CONFIRMED;
3f2a2989
 
4f692b41
 	if(subs->sockinfo_str.len) {
3f2a2989
 		int port, proto;
4f692b41
 		str host;
 		char *tmp;
 		if((tmp = as_asciiz(&subs->sockinfo_str)) == NULL) {
9f6e354b
 			LM_ERR("no pkg memory left\n");
 			goto error;
 		}
4f692b41
 		if(parse_phostport(tmp, &host.s, &host.len, &port, &proto)) {
9e2825a4
 			LM_ERR("bad sockinfo string\n");
9f6e354b
 			pkg_free(tmp);
3f2a2989
 			goto error;
 		}
4f692b41
 		td->send_sock = grep_sock_info(
 				&host, (unsigned short)port, (unsigned short)proto);
9f6e354b
 		pkg_free(tmp);
3f2a2989
 	}
ea2ce2da
 
467feeb2
 	return td;
 
ea2ce2da
 error:
57d3284f
 	ps_free_tm_dlg(td);
467feeb2
 	return NULL;
 }
 
4f692b41
 int get_subs_db(
 		str *pres_uri, pres_ev_t *event, str *sender, subs_t **s_array, int *n)
467feeb2
 {
0caecc44
 	db_key_t query_cols[7];
4f692b41
 	db_op_t query_ops[7];
0caecc44
 	db_val_t query_vals[7];
a3088218
 	db_key_t result_cols[21];
467feeb2
 	int n_result_cols = 0, n_query_cols = 0;
4f692b41
 	db_row_t *row;
 	db_val_t *row_vals;
e1615a19
 	db1_res_t *result = NULL;
b0a4bc00
 	int from_user_col, from_domain_col, from_tag_col;
 	int to_user_col, to_domain_col, to_tag_col;
4f692b41
 	int expires_col = 0, callid_col, cseq_col, i, reason_col;
 	int version_col = 0, record_route_col = 0, contact_col = 0;
 	int sockinfo_col = 0, local_contact_col = 0, event_id_col = 0;
 	int watcher_user_col = 0, watcher_domain_col = 0;
 	int flags_col = 0, user_agent_col = 0;
85de52fc
 	subs_t s, *s_new;
4f692b41
 	int inc = 0;
ea2ce2da
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
9e2825a4
 		LM_ERR("in use_table\n");
08897d77
 		return -1;
467feeb2
 	}
 
9e2825a4
 	LM_DBG("querying database table = active_watchers\n");
e2cf6343
 	query_cols[n_query_cols] = &str_presentity_uri_col;
467feeb2
 	query_ops[n_query_cols] = OP_EQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
85de52fc
 	query_vals[n_query_cols].val.str_val = *pres_uri;
467feeb2
 	n_query_cols++;
ea2ce2da
 
e2cf6343
 	query_cols[n_query_cols] = &str_event_col;
467feeb2
 	query_ops[n_query_cols] = OP_EQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
467feeb2
 	query_vals[n_query_cols].nul = 0;
85de52fc
 	query_vals[n_query_cols].val.str_val = event->name;
467feeb2
 	n_query_cols++;
 
e2cf6343
 	query_cols[n_query_cols] = &str_status_col;
7532087a
 	query_ops[n_query_cols] = OP_EQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_INT;
7532087a
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = ACTIVE_STATUS;
 	n_query_cols++;
 
a3dd1f8f
 	query_cols[n_query_cols] = &str_contact_col;
 	query_ops[n_query_cols] = OP_NEQ;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
a3dd1f8f
 	query_vals[n_query_cols].nul = 0;
4f692b41
 	if(sender) {
 		LM_DBG("Do not send Notify to:[uri]= %.*s\n", sender->len, sender->s);
85de52fc
 		query_vals[n_query_cols].val.str_val = *sender;
a3dd1f8f
 	} else {
 		query_vals[n_query_cols].val.str_val.s = "";
 		query_vals[n_query_cols].val.str_val.len = 0;
0caecc44
 	}
a3dd1f8f
 	n_query_cols++;
85de52fc
 
4f692b41
 	result_cols[to_user_col = n_result_cols++] = &str_to_user_col;
 	result_cols[to_domain_col = n_result_cols++] = &str_to_domain_col;
 	result_cols[from_user_col = n_result_cols++] = &str_from_user_col;
 	result_cols[from_domain_col = n_result_cols++] = &str_from_domain_col;
 	result_cols[watcher_user_col = n_result_cols++] = &str_watcher_username_col;
 	result_cols[watcher_domain_col = n_result_cols++] = &str_watcher_domain_col;
 	result_cols[event_id_col = n_result_cols++] = &str_event_id_col;
 	result_cols[from_tag_col = n_result_cols++] = &str_from_tag_col;
 	result_cols[to_tag_col = n_result_cols++] = &str_to_tag_col;
 	result_cols[callid_col = n_result_cols++] = &str_callid_col;
 	result_cols[cseq_col = n_result_cols++] = &str_local_cseq_col;
 	result_cols[record_route_col = n_result_cols++] = &str_record_route_col;
 	result_cols[contact_col = n_result_cols++] = &str_contact_col;
 	result_cols[expires_col = n_result_cols++] = &str_expires_col;
 	result_cols[reason_col = n_result_cols++] = &str_reason_col;
 	result_cols[sockinfo_col = n_result_cols++] = &str_socket_info_col;
 	result_cols[local_contact_col = n_result_cols++] = &str_local_contact_col;
 	result_cols[version_col = n_result_cols++] = &str_version_col;
 	result_cols[flags_col = n_result_cols++] = &str_flags_col;
 	result_cols[user_agent_col = n_result_cols++] = &str_user_agent_col;
 
 	if(pa_dbf.query(pa_db, query_cols, query_ops, query_vals, result_cols,
 			   n_query_cols, n_result_cols, 0, &result)
 			< 0) {
9e2825a4
 		LM_ERR("while querying database\n");
4f692b41
 		if(result) {
55cbbb0b
 			pa_dbf.free_result(pa_db, result);
8dab7008
 		}
08897d77
 		return -1;
467feeb2
 	}
 
4f692b41
 	if(result == NULL)
08897d77
 		return -1;
8dab7008
 
4f692b41
 	if(result->n <= 0) {
9e2825a4
 		LM_DBG("The query for subscribtion for [uri]= %.*s for [event]= %.*s"
4f692b41
 			   " returned no result\n",
 				pres_uri->len, pres_uri->s, event->name.len, event->name.s);
55cbbb0b
 		pa_dbf.free_result(pa_db, result);
08897d77
 		return 0;
467feeb2
 	}
9e2825a4
 	LM_DBG("found %d dialogs\n", result->n);
ea2ce2da
 
4f692b41
 	for(i = 0; i < result->n; i++) {
55cbbb0b
 		row = &result->rows[i];
ea2ce2da
 		row_vals = ROW_VALUES(row);
 
ae4856f3
 		if(row_vals[reason_col].val.string_val) {
4f692b41
 			if(strlen(row_vals[reason_col].val.string_val) != 0)
 				continue;
ae4856f3
 		}
 
8cc889d8
 		//	s.reason.len= strlen(s.reason.s);
85de52fc
 
8cc889d8
 		memset(&s, 0, sizeof(subs_t));
4f692b41
 		s.status = ACTIVE_STATUS;
ea2ce2da
 
4f692b41
 		s.pres_uri = *pres_uri;
 		s.to_user.s = (char *)row_vals[to_user_col].val.string_val;
 		s.to_user.len = strlen(s.to_user.s);
ea2ce2da
 
4f692b41
 		s.to_domain.s = (char *)row_vals[to_domain_col].val.string_val;
 		s.to_domain.len = strlen(s.to_domain.s);
ea2ce2da
 
4f692b41
 		s.from_user.s = (char *)row_vals[from_user_col].val.string_val;
 		s.from_user.len = strlen(s.from_user.s);
ea2ce2da
 
4f692b41
 		s.from_domain.s = (char *)row_vals[from_domain_col].val.string_val;
 		s.from_domain.len = strlen(s.from_domain.s);
63ab6b48
 
4f692b41
 		s.watcher_user.s = (char *)row_vals[watcher_user_col].val.string_val;
 		s.watcher_user.len = strlen(s.watcher_user.s);
ea2ce2da
 
4f692b41
 		s.watcher_domain.s =
 				(char *)row_vals[watcher_domain_col].val.string_val;
 		s.watcher_domain.len = strlen(s.watcher_domain.s);
ea2ce2da
 
4f692b41
 		s.event_id.s = (char *)row_vals[event_id_col].val.string_val;
 		s.event_id.len = (s.event_id.s) ? strlen(s.event_id.s) : 0;
ea2ce2da
 
4f692b41
 		s.to_tag.s = (char *)row_vals[to_tag_col].val.string_val;
 		s.to_tag.len = strlen(s.to_tag.s);
ea2ce2da
 
4f692b41
 		s.from_tag.s = (char *)row_vals[from_tag_col].val.string_val;
 		s.from_tag.len = strlen(s.from_tag.s);
ea2ce2da
 
4f692b41
 		s.callid.s = (char *)row_vals[callid_col].val.string_val;
 		s.callid.len = strlen(s.callid.s);
ea2ce2da
 
4f692b41
 		s.record_route.s = (char *)row_vals[record_route_col].val.string_val;
 		s.record_route.len = (s.record_route.s) ? strlen(s.record_route.s) : 0;
6059779b
 
4f692b41
 		s.contact.s = (char *)row_vals[contact_col].val.string_val;
 		s.contact.len = strlen(s.contact.s);
ea2ce2da
 
4f692b41
 		s.sockinfo_str.s = (char *)row_vals[sockinfo_col].val.string_val;
 		s.sockinfo_str.len = s.sockinfo_str.s ? strlen(s.sockinfo_str.s) : 0;
3f2a2989
 
4f692b41
 		s.local_contact.s = (char *)row_vals[local_contact_col].val.string_val;
 		s.local_contact.len = s.local_contact.s ? strlen(s.local_contact.s) : 0;
ea2ce2da
 
4f692b41
 		s.event = event;
 		s.local_cseq = row_vals[cseq_col].val.int_val + 1;
fe0e0b89
 		if(row_vals[expires_col].val.int_val < (int)time(NULL) + pres_expires_offset)
4f692b41
 			s.expires = 0;
ae4856f3
 		else
4f692b41
 			s.expires = row_vals[expires_col].val.int_val - (int)time(NULL);
 		s.version = row_vals[version_col].val.int_val + 1;
a3088218
 		s.flags = row_vals[flags_col].val.int_val;
4f692b41
 		s.user_agent.s = (char *)row_vals[user_agent_col].val.string_val;
 		s.user_agent.len = (s.user_agent.s) ? strlen(s.user_agent.s) : 0;
85de52fc
 
4f692b41
 		s_new = mem_copy_subs(&s, PKG_MEM_TYPE);
 		if(s_new == NULL) {
9e2825a4
 			LM_ERR("while copying subs_t structure\n");
a5d04f23
 			goto error;
55cbbb0b
 		}
4f692b41
 		s_new->next = (*s_array);
 		(*s_array) = s_new;
703ca032
 		printf_subs(s_new);
08124c58
 		inc++;
55cbbb0b
 	}
 	pa_dbf.free_result(pa_db, result);
4f692b41
 	*n = inc;
55cbbb0b
 
08897d77
 	return 0;
a5d04f23
 
 error:
55cbbb0b
 	if(result)
 		pa_dbf.free_result(pa_db, result);
ea2ce2da
 
08897d77
 	return -1;
85de52fc
 }
 
4f692b41
 subs_t *get_subs_dialog(str *pres_uri, pres_ev_t *event, str *sender)
85de52fc
 {
 	unsigned int hash_code;
4f692b41
 	subs_t *s = NULL, *s_new;
 	subs_t *s_array = NULL;
 	int n = 0;
ea2ce2da
 
fe0e0b89
 	/* if pres_subs_dbmode!=DB_ONLY, should take the subscriptions from the
 		hashtable only in DB_ONLY mode should take all dialogs from db */
85de52fc
 
fe0e0b89
 	if(pres_subs_dbmode == DB_ONLY) {
4f692b41
 		if(get_subs_db(pres_uri, event, sender, &s_array, &n) < 0) {
9e2825a4
 			LM_ERR("getting dialogs from database\n");
85de52fc
 			goto error;
 		}
4f692b41
 	} else {
 		hash_code = core_case_hash(pres_uri, &event->name, shtable_size);
ea2ce2da
 
35568faf
 		lock_get(&subs_htable[hash_code].lock);
85de52fc
 
4f692b41
 		s = subs_htable[hash_code].entries;
35568faf
 
4f692b41
 		while(s->next) {
 			s = s->next;
ae86ca36
 
35568faf
 			printf_subs(s);
ae86ca36
 
4f692b41
 			if(s->expires < (int)time(NULL)) {
35568faf
 				LM_DBG("expired subs\n");
85de52fc
 				continue;
6afdbf4a
 			}
ae86ca36
 
4f692b41
 			if((!(s->status == ACTIVE_STATUS && s->reason.len == 0
 					   && s->event == event && s->pres_uri.len == pres_uri->len
 					   && presence_sip_uri_match(&s->pres_uri, pres_uri) == 0))
 					|| (sender && sender->len == s->contact.len
 							   && presence_sip_uri_match(sender, &s->contact)
 										  == 0))
35568faf
 				continue;
 
4f692b41
 			s_new = mem_copy_subs(s, PKG_MEM_TYPE);
 			if(s_new == NULL) {
35568faf
 				LM_ERR("copying subs_t structure\n");
 				lock_release(&subs_htable[hash_code].lock);
 				goto error;
 			}
4f692b41
 			s_new->expires -= (int)time(NULL);
 			s_new->next = s_array;
 			s_array = s_new;
85de52fc
 		}
ae86ca36
 		lock_release(&subs_htable[hash_code].lock);
35568faf
 	}
85de52fc
 
 	return s_array;
 
 error:
5cde1b04
 	free_subs_list(s_array, PKG_MEM_TYPE, 0);
85de52fc
 	return NULL;
467feeb2
 }
85de52fc
 
4f692b41
 int publ_notify(presentity_t *p, str pres_uri, str *body, str *offline_etag,
 		str *rules_doc)
651016d6
 {
b429f625
 	str *notify_body = NULL;
4f692b41
 	subs_t *subs_array = NULL, *s = NULL;
 	int ret_code = -1;
651016d6
 
4f692b41
 	subs_array = get_subs_dialog(&pres_uri, p->event, p->sender);
 	if(subs_array == NULL) {
9e2825a4
 		LM_DBG("Could not find subs_dialog\n");
4f692b41
 		ret_code = 0;
651016d6
 		goto done;
 	}
 
 	/* if the event does not require aggregation - we have the final body */
4f692b41
 	if(p->event->agg_nbody) {
 		notify_body = get_p_notify_body(pres_uri, p->event, offline_etag, NULL);
 		if(notify_body == NULL) {
9e2825a4
 			LM_DBG("Could not get the notify_body\n");
651016d6
 			/* goto error; */
 		}
 	}
8ebd442a
 
4f692b41
 	s = subs_array;
 	while(s) {
 		s->auth_rules_doc = rules_doc;
8ebd442a
 
4f692b41
 		if(notify(s, NULL, notify_body ? notify_body : body, 0,
 				   p->event->aux_body_processing)
 				< 0) {
 			LM_ERR("Could not send notify for %.*s\n", p->event->name.len,
 					p->event->name.s);
651016d6
 		}
8ebd442a
 
4f692b41
 		s = s->next;
651016d6
 	}
4f692b41
 	ret_code = 0;
651016d6
 
 done:
5cde1b04
 	free_subs_list(subs_array, PKG_MEM_TYPE, 0);
ea2ce2da
 	free_notify_body(notify_body, p->event);
85de52fc
 	return ret_code;
8485536f
 }
 
 int publ_notify_notifier(str pres_uri, pres_ev_t *event)
 {
 	db_key_t query_cols[2], result_cols[3];
 	db_val_t query_vals[2], *values;
 	db_row_t *rows;
 	db1_res_t *result = NULL;
 	int n_query_cols = 0, n_result_cols = 0;
 	int r_callid_col = 0, r_to_tag_col = 0, r_from_tag_col = 0;
 	int i;
 	int ret = -1;
 	subs_t subs;
34cd2acb
 	db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
8485536f
 
4f692b41
 	if(pa_db == NULL) {
8485536f
 		LM_ERR("null database connection\n");
 		goto error;
 	}
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	query_cols[n_query_cols] = &str_presentity_uri_col;
8485536f
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = pres_uri;
 	n_query_cols++;
 
4f692b41
 	query_cols[n_query_cols] = &str_event_col;
8485536f
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = event->name;
 	n_query_cols++;
 
4f692b41
 	result_cols[r_callid_col = n_result_cols++] = &str_callid_col;
 	result_cols[r_to_tag_col = n_result_cols++] = &str_to_tag_col;
 	result_cols[r_from_tag_col = n_result_cols++] = &str_from_tag_col;
8485536f
 
4f692b41
 	if(query_fn(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
 			   n_result_cols, 0, &result)
 			< 0) {
8485536f
 		LM_ERR("Can't query db\n");
 		goto error;
 	}
 
4f692b41
 	if(result == NULL) {
e2f65408
 		LM_ERR("bad result\n");
 		goto error;
 	}
8485536f
 
e2f65408
 	rows = RES_ROWS(result);
4f692b41
 	for(i = 0; i < RES_ROW_N(result); i++) {
e2f65408
 		values = ROW_VALUES(&rows[i]);
8485536f
 
4f692b41
 		subs.callid.s = (char *)VAL_STRING(&values[r_callid_col]);
8485536f
 		subs.callid.len = strlen(subs.callid.s);
4f692b41
 		subs.to_tag.s = (char *)VAL_STRING(&values[r_to_tag_col]);
8485536f
 		subs.to_tag.len = strlen(subs.to_tag.s);
4f692b41
 		subs.from_tag.s = (char *)VAL_STRING(&values[r_from_tag_col]);
8485536f
 		subs.from_tag.len = strlen(subs.from_tag.s);
 
 		set_updated(&subs);
 	}
 
 	ret = RES_ROW_N(result);
 
 error:
4f692b41
 	if(result)
 		pa_dbf.free_result(pa_db, result);
34cd2acb
 
8485536f
 	return ret;
 }
651016d6
 
4f692b41
 int query_db_notify(str *pres_uri, pres_ev_t *event, subs_t *watcher_subs)
467feeb2
 {
4f692b41
 	subs_t *subs_array = NULL, *s = NULL;
 	str *notify_body = NULL, *aux_body = NULL;
 	int ret_code = -1;
467feeb2
 
4f692b41
 	subs_array = get_subs_dialog(pres_uri, event, NULL);
 	if(subs_array == NULL) {
9e2825a4
 		LM_DBG("Could not get subscription dialog\n");
4f692b41
 		ret_code = 1;
08897d77
 		goto done;
 	}
467feeb2
 
4f692b41
 	s = subs_array;
8ebd442a
 
4f692b41
 	if(pres_notifier_processes > 0) {
 		while(s) {
258bc7e2
 			set_updated(s);
4f692b41
 			s = s->next;
467feeb2
 		}
4f692b41
 	} else {
258bc7e2
 		if(event->type & PUBL_TYPE)
 			notify_body = get_p_notify_body(*pres_uri, event, NULL, NULL);
8ebd442a
 
4f692b41
 		while(s) {
ea2ce2da
 
4f692b41
 			if(event->aux_body_processing) {
258bc7e2
 				aux_body = event->aux_body_processing(s, notify_body);
8ebd442a
 			}
ea2ce2da
 
4f692b41
 			if(notify(s, watcher_subs, aux_body ? aux_body : notify_body, 0, 0)
 					< 0) {
258bc7e2
 				LM_ERR("Could not send notify for [event]=%.*s\n",
 						event->name.len, event->name.s);
 				goto done;
 			}
ea2ce2da
 
4f692b41
 			if(aux_body != NULL) {
 				if(aux_body->s) {
258bc7e2
 					event->aux_free_body(aux_body->s);
 				}
 				pkg_free(aux_body);
 			}
4f692b41
 			s = s->next;
8ebd442a
 		}
467feeb2
 	}
a5d04f23
 
4f692b41
 	ret_code = 1;
08897d77
 
85de52fc
 done:
5cde1b04
 	free_subs_list(subs_array, PKG_MEM_TYPE, 0);
bd598ce9
 	free_notify_body(notify_body, event);
467feeb2
 
85de52fc
 	return ret_code;
467feeb2
 }
 
4f692b41
 int send_notify_request(
 		subs_t *subs, subs_t *watcher_subs, str *n_body, int force_null_body)
467feeb2
 {
4f692b41
 	dlg_t *td = NULL;
467feeb2
 	str met = {"NOTIFY", 6};
a3dd1f8f
 	str str_hdr = {0, 0};
4f692b41
 	str *notify_body = NULL;
 	int result = 0;
 	subs_t *cb_param = NULL;
 	str *final_body = NULL;
b98dfaa7
 	uac_req_t uac_r;
4f692b41
 	str *aux_body = NULL;
 	subs_t *backup_subs = NULL;
ea2ce2da
 
9e2825a4
 	LM_DBG("dialog info:\n");
467feeb2
 	printf_subs(subs);
 
8485536f
 	/* getting the status of the subscription */
f42f79bf
 
4f692b41
 	if(force_null_body) {
76d785b5
 		goto jump_over_body;
8aa8a6d8
 	}
76d785b5
 
4f692b41
 	if(n_body != NULL && subs->status == ACTIVE_STATUS) {
 		if(subs->event->req_auth) {
ea2ce2da
 
4f692b41
 			if(subs->auth_rules_doc && subs->event->apply_auth_nbody) {
 				if(subs->event->apply_auth_nbody(n_body, subs, &notify_body)
 						< 0) {
a3dd1f8f
 					LM_ERR("in function apply_auth_nbody\n");
 					goto error;
 				}
f42f79bf
 			}
4f692b41
 			if(notify_body == NULL)
 				notify_body = n_body;
 		} else
 			notify_body = n_body;
 	} else {
 		if(subs->status == TERMINATED_STATUS
 				|| subs->status == PENDING_STATUS) {
9e2825a4
 			LM_DBG("state terminated or pending- notify body NULL\n");
467feeb2
 			notify_body = NULL;
4f692b41
 		} else {
 			if(subs->event->type & WINFO_TYPE) {
85c6efd9
 				notify_body = get_wi_notify_body(subs, watcher_subs);
4f692b41
 				if(notify_body == NULL) {
9e2825a4
 					LM_DBG("Could not get notify_body\n");
467feeb2
 					goto error;
 				}
4f692b41
 			} else {
 				notify_body = get_p_notify_body(subs->pres_uri, subs->event,
 						NULL, (subs->contact.s) ? &subs->contact : NULL);
 				if(notify_body == NULL || notify_body->s == NULL) {
9e2825a4
 					LM_DBG("Could not get the notify_body\n");
4f692b41
 				} else {
cfef15ef
 					/* call aux_body_processing if exists */
4f692b41
 					if(subs->event->aux_body_processing) {
 						aux_body = subs->event->aux_body_processing(
 								subs, notify_body);
1682896e
 						if(aux_body) {
b6b7de88
 							free_notify_body(notify_body, subs->event);
1682896e
 							notify_body = aux_body;
 						}
467feeb2
 					}
cfef15ef
 
 					/* apply authorization rules if exists */
4f692b41
 					if(subs->event->req_auth) {
cfef15ef
 						if(subs->auth_rules_doc && subs->event->apply_auth_nbody
4f692b41
 								&& subs->event->apply_auth_nbody(
 										   notify_body, subs, &final_body)
 										   < 0) {
cfef15ef
 							LM_ERR("in function apply_auth\n");
 							goto error;
 						}
4f692b41
 						if(final_body) {
cfef15ef
 							xmlFree(notify_body->s);
 							pkg_free(notify_body);
4f692b41
 							notify_body = final_body;
cfef15ef
 						}
703ca032
 					}
 				}
 			}
467feeb2
 		}
 	}
ae86ca36
 
76d785b5
 jump_over_body:
 
4f692b41
 	if(subs->expires <= 0) {
 		subs->expires = 0;
 		subs->status = TERMINATED_STATUS;
 		subs->reason.s = "timeout";
 		subs->reason.len = 7;
e806dc85
 	}
 
ba45136f
 	/* build extra headers */
b0125b66
 	if(build_str_hdr(subs, (notify_body && notify_body->len>0) ? 1 : 0,
 				&str_hdr) < 0) {
9e2825a4
 		LM_ERR("while building headers\n");
ba45136f
 		goto error;
ae86ca36
 	}
a3dd1f8f
 	LM_DBG("headers:\n%.*s\n", str_hdr.len, str_hdr.s);
ba45136f
 
467feeb2
 	/* construct the dlg_t structure */
57d3284f
 	td = ps_build_dlg_t(subs);
4f692b41
 	if(td == NULL) {
9e2825a4
 		LM_ERR("while building dlg_t structure\n");
ae86ca36
 		goto error;
467feeb2
 	}
 
ae86ca36
 	LM_DBG("expires %d status %d\n", subs->expires, subs->status);
a3088218
 	cb_param = mem_copy_subs(subs, SHM_MEM_TYPE);
49b2cc3a
 
fb9351aa
 	if(_pres_subs_mode==1) {
 		backup_subs = _pres_subs_last_sub;
 		_pres_subs_last_sub = subs;
 	}
9034787e
 
e8990060
 	set_uac_req(&uac_r, &met, &str_hdr, notify_body, td, TMCB_LOCAL_COMPLETED,
4f692b41
 			p_tm_callback, (void *)cb_param);
b98dfaa7
 	result = tmb.t_request_within(&uac_r);
fb9351aa
 	if(_pres_subs_mode==1) {
 		_pres_subs_last_sub = backup_subs;
 	}
4f692b41
 	if(result < 0) {
9e2825a4
 		LM_ERR("in function tmb.t_request_within\n");
ae86ca36
 		if(cb_param)
a3088218
 			shm_free(cb_param);
ae86ca36
 		goto error;
467feeb2
 	}
567f0c6b
 
aa4c37ab
 	LM_GEN2(pres_local_log_facility, pres_local_log_level,
4f692b41
 			"NOTIFY %.*s via %.*s on behalf of %.*s for event %.*s : %.*s\n",
 			td->rem_uri.len, td->rem_uri.s, td->hooks.next_hop->len,
 			td->hooks.next_hop->s, td->loc_uri.len, td->loc_uri.s,
 			subs->event->name.len, subs->event->name.s, subs->callid.len,
 			subs->callid.s);
567f0c6b
 
57d3284f
 	ps_free_tm_dlg(td);
ea2ce2da
 
4f692b41
 	if(str_hdr.s)
 		pkg_free(str_hdr.s);
ea2ce2da
 
4f692b41
 	if((int)(long)n_body != (int)(long)notify_body)
bd598ce9
 		free_notify_body(notify_body, subs->event);
 
467feeb2
 	return 0;
 
 error:
57d3284f
 	ps_free_tm_dlg(td);
4f692b41
 	if(str_hdr.s != NULL)
a3dd1f8f
 		pkg_free(str_hdr.s);
4f692b41
 	if((int)(long)n_body != (int)(long)notify_body) {
 		if(notify_body != NULL) {
 			if(notify_body->s != NULL) {
 				if(subs->event->type & WINFO_TYPE)
0b78a8ac
 					xmlFree(notify_body->s);
4f692b41
 				else if(subs->event->apply_auth_nbody == NULL
 						&& subs->event->agg_nbody == NULL)
0b78a8ac
 					pkg_free(notify_body->s);
 				else
4f692b41
 					subs->event->free_body(notify_body->s);
0b78a8ac
 			}
f42f79bf
 			pkg_free(notify_body);
467feeb2
 		}
ae86ca36
 	}
467feeb2
 	return -1;
85de52fc
 }
467feeb2
 
85de52fc
 
4f692b41
 int notify(subs_t *subs, subs_t *watcher_subs, str *n_body, int force_null_body,
 		aux_body_processing_t *aux_body_processing)
85de52fc
 {
b429f625
 
4f692b41
 	str *aux_body = NULL;
b429f625
 
6afdbf4a
 	/* update first in hash table and the send Notify */
4f692b41
 	if(subs->expires != 0 && subs->status != TERMINATED_STATUS) {
2254abe7
 		unsigned int hash_code;
4f692b41
 		hash_code = core_case_hash(
 				&subs->pres_uri, &subs->event->name, shtable_size);
2254abe7
 
35568faf
 		/* if subscriptions are held also in memory, update the subscription hashtable */
fe0e0b89
 		if(pres_subs_dbmode != DB_ONLY) {
4f692b41
 			if(update_shtable(subs_htable, hash_code, subs, LOCAL_TYPE) < 0) {
35568faf
 				/* subscriptions are held only in memory, and hashtable update failed */
 				LM_ERR("updating subscription record in hash table\n");
 				return -1;
85de52fc
 			}
35568faf
 		}
ae86ca36
 		/* if DB_ONLY mode or WRITE_THROUGH update in database */
4f692b41
 		if(subs->recv_event != PRES_SUBSCRIBE_RECV
fe0e0b89
 				&& ((pres_subs_dbmode == DB_ONLY && pres_notifier_processes == 0)
 						   || pres_subs_dbmode == WRITE_THROUGH)) {
35568faf
 			LM_DBG("updating subscription to database\n");
4f692b41
 			if(update_subs_db(subs, LOCAL_TYPE) < 0) {
35568faf
 				LM_ERR("updating subscription in database\n");
85de52fc
 				return -1;
 			}
 		}
 	}
ae86ca36
 
4f692b41
 	if(subs->reason.s && subs->status == ACTIVE_STATUS && subs->reason.len == 12
 			&& strncmp(subs->reason.s, "polite-block", 12) == 0) {
35568faf
 		force_null_body = 1;
 	}
6afdbf4a
 
4f692b41
 	if(!force_null_body && aux_body_processing) {
b429f625
 		aux_body = aux_body_processing(subs, n_body);
 	}
 
4f692b41
 	if(send_notify_request(subs, watcher_subs, aux_body ? aux_body : n_body,
 			   force_null_body)
 			< 0) {
9e2825a4
 		LM_ERR("sending Notify not successful\n");
4f692b41
 		if(aux_body != NULL) {
b429f625
 			if(aux_body->s) {
 				subs->event->aux_free_body(aux_body->s);
 			}
 			pkg_free(aux_body);
 		}
6afdbf4a
 		return -1;
 	}
b429f625
 
4f692b41
 	if(aux_body != NULL) {
b429f625
 		if(aux_body->s) {
 			subs->event->aux_free_body(aux_body->s);
 		}
 		pkg_free(aux_body);
 	}
a6357f83
 	return 0;
467feeb2
 }
 
72d3230c
 static sip_msg_t *_pres_subs_notify_reply_msg = NULL;
 static int _pres_subs_notify_reply_code = 0;
a3088218
 
 int pv_parse_notify_reply_var_name(pv_spec_p sp, str *in)
 {
4f692b41
 	pv_spec_t *pv = NULL;
 	if(in->s == NULL || in->len <= 0)
a3088218
 		return -1;
4f692b41
 	pv = (pv_spec_t *)pkg_malloc(sizeof(pv_spec_t));
 	if(pv == NULL)
a3088218
 		return -1;
 	memset(pv, 0, sizeof(pv_spec_t));
4f692b41
 	if(pv_parse_spec(in, pv) == NULL)
a3088218
 		goto error;
4f692b41
 	sp->pvp.pvn.u.dname = (void *)pv;
a3088218
 	sp->pvp.pvn.type = PV_NAME_PVAR;
 	return 0;
 
 error:
 	LM_ERR("invalid pv name [%.*s]\n", in->len, in->s);
4f692b41
 	if(pv != NULL)
a3088218
 		pkg_free(pv);
 	return -1;
 }
 
4f692b41
 int pv_get_notify_reply(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
467feeb2
 {
4f692b41
 	pv_spec_t *pv = NULL;
ae86ca36
 
4f692b41
 	if(msg == NULL)
a3088218
 		return 1;
 
4f692b41
 	pv = (pv_spec_t *)param->pvn.u.dname;
 	if(pv == NULL)
a3088218
 		return pv_get_null(msg, param, res);
 
 	return pv_get_spec_value(_pres_subs_notify_reply_msg, pv, res);
 }
 
4f692b41
 #define FAKED_SIP_408_MSG_FORMAT                                  \
 	"SIP/2.0 408 TIMEOUT\r\nVia: SIP/2.0/UDP 127.0.0.1\r\nFrom: " \
 	"invalid;\r\nTo: invalid\r\nCall-ID: invalid\r\nCSeq: 1 "     \
 	"TIMEOUT\r\nContent-Length: 0\r\n\r\n"
 static sip_msg_t *_faked_msg = NULL;
a3088218
 
4f692b41
 sip_msg_t *faked_msg()
 {
a3088218
 	if(_faked_msg == NULL) {
 		_faked_msg = pkg_malloc(sizeof(sip_msg_t));
4f692b41
 		if(likely(build_sip_msg_from_buf(_faked_msg, FAKED_SIP_408_MSG_FORMAT,
 						  strlen(FAKED_SIP_408_MSG_FORMAT), inc_msg_no())
 				   < 0)) {
a3088218
 			LM_ERR("failed to parse msg buffer\n");
 			return NULL;
 		}
 	}
 	return _faked_msg;
 }
 
 void run_notify_reply_event(struct cell *t, struct tmcb_params *ps)
 {
 	int backup_route_type;
4f692b41
 	subs_t *backup_subs = NULL;
a3088218
 	sip_msg_t msg;
 
4f692b41
 	if(goto_on_notify_reply == -1)
a3088218
 		return;
 
4f692b41
 	if(likely(build_sip_msg_from_buf(&msg, t->uac->request.buffer,
 					  t->uac->request.buffer_len, inc_msg_no())
 			   < 0)) {
a3088218
 		LM_ERR("failed to parse msg buffer\n");
467feeb2
 		return;
 	}
 
a3088218
 	_pres_subs_notify_reply_code = ps->code;
4f692b41
 	if(ps->code == 408 || ps->rpl == NULL) {
a3088218
 		_pres_subs_notify_reply_msg = faked_msg();
 	} else {
 		_pres_subs_notify_reply_msg = ps->rpl;
 	}
 
fb9351aa
 	if(_pres_subs_mode==1) {
 		backup_subs = _pres_subs_last_sub;
 		_pres_subs_last_sub = mem_copy_subs((subs_t *)(*ps->param), PKG_MEM_TYPE);
 	}
a3088218
 
 	backup_route_type = get_route_type();
 	set_route_type(LOCAL_ROUTE);
 	run_top_route(event_rt.rlist[goto_on_notify_reply], &msg, 0);
 	set_route_type(backup_route_type);
 
 	_pres_subs_notify_reply_msg = NULL;
 	_pres_subs_notify_reply_code = 0;
fb9351aa
 	if(_pres_subs_mode==1) {
 		pkg_free(_pres_subs_last_sub);
 		_pres_subs_last_sub = backup_subs;
 	}
a3088218
 	free_sip_msg(&msg);
 }
 
1dfe265a
 int pres_get_delete_sub(void)
 {
4f692b41
 	sr_xavp_t *vavp = NULL;
 	str vname = str_init("delete_subscription");
1dfe265a
 
4f692b41
 	if(pres_xavp_cfg.s == NULL || pres_xavp_cfg.len <= 0) {
 		return 0;
 	}
1dfe265a
 
4f692b41
 	vavp = xavp_get_child_with_ival(&pres_xavp_cfg, &vname);
 	if(vavp != NULL) {
 		return (int)vavp->val.v.i;
 	}
1dfe265a
 
4f692b41
 	return 0;
1dfe265a
 }
 
4f692b41
 void p_tm_callback(struct cell *t, int type, struct tmcb_params *ps)
a3088218
 {
4f692b41
 	subs_t *subs;
a3088218
 
 	if(ps->param == NULL || *ps->param == NULL) {
4f692b41
 		LM_ERR("weird shit happening\n");
 		if(ps->param != NULL && *ps->param != NULL)
 			shm_free((subs_t *)(*ps->param));
 		return;
a3088218
 	}
 
4f692b41
 	subs = (subs_t *)(*ps->param);
 	LM_DBG("completed with status %d [to_tag:%.*s]\n", ps->code,
 			subs->to_tag.len, subs->to_tag.s);
a3088218
 
 	run_notify_reply_event(t, ps);
85de52fc
 
4f692b41
 	if(ps->code == 404 || ps->code == 481
fe0e0b89
 			|| (ps->code == 408 && pres_timeout_rm_subs
4f692b41
 					   && subs->status != TERMINATED_STATUS)
 			|| pres_get_delete_sub()) {
 		delete_subs(&subs->pres_uri, &subs->event->name, &subs->to_tag,
 				&subs->from_tag, &subs->callid);
a3088218
 	}
467feeb2
 
a3088218
 	shm_free(subs);
467feeb2
 }
 
4f692b41
 void free_cbparam(c_back_param *cb_param)
467feeb2
 {
4f692b41
 	if(cb_param != NULL)
85de52fc
 		shm_free(cb_param);
 }
467feeb2
 
4f692b41
 c_back_param *shm_dup_cbparam(subs_t *subs)
85de52fc
 {
a3dd1f8f
 	int size;
4f692b41
 	c_back_param *cb_param = NULL;
ea2ce2da
 
4f692b41
 	size = sizeof(c_back_param) + subs->pres_uri.len + subs->event->name.len
 		   + subs->to_tag.len + subs->from_tag.len + subs->callid.len;
3f2a2989
 
4f692b41
 	cb_param = (c_back_param *)shm_malloc(size);
 	LM_DBG("=== %d/%d/%d\n", subs->pres_uri.len, subs->event->name.len,
 			subs->to_tag.len);
 	if(cb_param == NULL) {
a3dd1f8f
 		LM_ERR("no more shared memory\n");
 		return NULL;
467feeb2
 	}
a3dd1f8f
 	memset(cb_param, 0, size);
467feeb2
 
4f692b41
 	cb_param->pres_uri.s = (char *)cb_param + sizeof(c_back_param);
85de52fc
 	memcpy(cb_param->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len);
a3dd1f8f
 	cb_param->pres_uri.len = subs->pres_uri.len;
4f692b41
 	cb_param->ev_name.s =
 			(char *)(cb_param->pres_uri.s) + cb_param->pres_uri.len;
a3dd1f8f
 	memcpy(cb_param->ev_name.s, subs->event->name.s, subs->event->name.len);
 	cb_param->ev_name.len = subs->event->name.len;
4f692b41
 	cb_param->to_tag.s = (char *)(cb_param->ev_name.s) + cb_param->ev_name.len;
a3dd1f8f
 	memcpy(cb_param->to_tag.s, subs->to_tag.s, subs->to_tag.len);
 	cb_param->to_tag.len = subs->to_tag.len;
467feeb2
 
4f692b41
 	cb_param->from_tag.s = (char *)(cb_param->to_tag.s) + cb_param->to_tag.len;
5ccf1eed
 	memcpy(cb_param->from_tag.s, subs->from_tag.s, subs->from_tag.len);
 	cb_param->from_tag.len = subs->from_tag.len;
 
4f692b41
 	cb_param->callid.s =
 			(char *)(cb_param->from_tag.s) + cb_param->from_tag.len;
5ccf1eed
 	memcpy(cb_param->callid.s, subs->callid.s, subs->callid.len);
 	cb_param->callid.len = subs->callid.len;
 
467feeb2
 	return cb_param;
 }
 
 
4f692b41
 str *create_winfo_xml(watcher_t *watchers, char *version, str resource,
 		str event, int STATE_FLAG)
f42f79bf
 {
ea2ce2da
 	xmlDocPtr doc = NULL;
4f692b41
 	xmlNodePtr root_node = NULL, node = NULL;
ea2ce2da
 	xmlNodePtr w_list_node = NULL;
f42f79bf
 	char content[200];
4f692b41
 	str *body = NULL;
 	char *res = NULL;
 	watcher_t *w;
f42f79bf
 
4f692b41
 	LIBXML_TEST_VERSION;
ea2ce2da
 
85de52fc
 	doc = xmlNewDoc(BAD_CAST "1.0");
4f692b41
 	root_node = xmlNewNode(NULL, BAD_CAST "watcherinfo");
 	xmlDocSetRootElement(doc, root_node);
f42f79bf
 
4f692b41
 	xmlNewProp(root_node, BAD_CAST "xmlns",
f42f79bf
 			BAD_CAST "urn:ietf:params:xml:ns:watcherinfo");
4f692b41
 	xmlNewProp(root_node, BAD_CAST "version", BAD_CAST version);
ea2ce2da
 
4f692b41
 	if(STATE_FLAG & FULL_STATE_FLAG) {
 		if(xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "full") == NULL) {
9e2825a4
 			LM_ERR("while adding new attribute\n");
f42f79bf
 			goto error;
 		}
4f692b41
 	} else {
 		if(xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial")
 				== NULL) {
9e2825a4
 			LM_ERR("while adding new attribute\n");
f42f79bf
 			goto error;
 		}
 	}
 
4f692b41
 	w_list_node = xmlNewChild(root_node, NULL, BAD_CAST "watcher-list", NULL);
 	if(w_list_node == NULL) {
9e2825a4
 		LM_ERR("while adding child\n");
f42f79bf
 		goto error;
 	}
4f692b41
 	res = (char *)pkg_malloc(MAX_unsigned(resource.len, event.len) + 1);
 	if(res == NULL) {
9e2825a4
 		ERR_MEM(PKG_MEM_STR);
85de52fc
 	}
 	memcpy(res, resource.s, resource.len);
4f692b41
 	res[resource.len] = '\0';
85de52fc
 	xmlNewProp(w_list_node, BAD_CAST "resource", BAD_CAST res);
a3dd1f8f
 	memcpy(res, event.s, event.len);
4f692b41
 	res[event.len] = '\0';
a3dd1f8f
 	xmlNewProp(w_list_node, BAD_CAST "package", BAD_CAST res);
85de52fc
 	pkg_free(res);
 
a3dd1f8f
 
4f692b41
 	w = watchers->next;
 	while(w) {
 		strncpy(content, w->uri.s, w->uri.len);
 		content[w->uri.len] = '\0';
 		node = xmlNewChild(
 				w_list_node, NULL, BAD_CAST "watcher", BAD_CAST content);
 		if(node == NULL) {
9e2825a4
 			LM_ERR("while adding child\n");
f42f79bf
 			goto error;
 		}
4f692b41
 		if(xmlNewProp(node, BAD_CAST "id", BAD_CAST w->id.s) == NULL) {
9e2825a4
 			LM_ERR("while adding new attribute\n");
f42f79bf
 			goto error;
ea2ce2da
 		}
 
4f692b41
 		if(xmlNewProp(node, BAD_CAST "event", BAD_CAST "subscribe") == NULL) {
9e2825a4
 			LM_ERR("while adding new attribute\n");
f42f79bf
 			goto error;
ea2ce2da
 		}
 
4f692b41
 		if(xmlNewProp(
 				   node, BAD_CAST "status", BAD_CAST get_status_str(w->status))
 				== NULL) {
9e2825a4
 			LM_ERR("while adding new attribute\n");
f42f79bf
 			goto error;
85de52fc
 		}
4f692b41
 		w = w->next;
f42f79bf
 	}
4f692b41
 	body = (str *)pkg_malloc(sizeof(str));
 	if(body == NULL) {
ea2ce2da
 		ERR_MEM(PKG_MEM_STR);
85de52fc
 	}
 	memset(body, 0, sizeof(str));
 
4f692b41
 	xmlDocDumpFormatMemory(doc, (xmlChar **)(void *)&body->s, &body->len, 1);
f42f79bf
 
85de52fc
 	xmlFreeDoc(doc);
f42f79bf
 
85de52fc
 	xmlCleanupParser();
f42f79bf
 
4f692b41
 	xmlMemoryDump();
f42f79bf
 
4f692b41
 	return body;
f42f79bf
 
 error:
4f692b41
 	if(doc)
f42f79bf
 		xmlFreeDoc(doc);
 	return NULL;
 }
 
4f692b41
 int watcher_found_in_list(watcher_t *watchers, str wuri)
a3dd1f8f
 {
4f692b41
 	watcher_t *w;
a3dd1f8f
 
 	w = watchers->next;
 
4f692b41
 	while(w) {
 		if(w->uri.len == wuri.len
 				&& presence_sip_uri_match(&w->uri, &wuri) == 0)
a3dd1f8f
 			return 1;
4f692b41
 		w = w->next;
a3dd1f8f
 	}
 
 	return 0;
 }
 
 int add_waiting_watchers(watcher_t *watchers, str pres_uri, str event)
 {
4f692b41
 	watcher_t *w;
a3dd1f8f
 	db_key_t query_cols[3];
 	db_val_t query_vals[3];
 	db_key_t result_cols[2];
e1615a19
 	db1_res_t *result = NULL;
4f692b41
 	db_row_t *row = NULL;
a3dd1f8f
 	db_val_t *row_vals;
 	int n_result_cols = 0;
 	int n_query_cols = 0;
 	int wuser_col, wdomain_col;
 	str wuser, wdomain, wuri;
 	int i;
 
 	/* select from watchers table the users that have subscribed
 	 * to the presentity and have status pending */
 
 	query_cols[n_query_cols] = &str_presentity_uri_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
a3dd1f8f
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = pres_uri;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_STR;
a3dd1f8f
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = event;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_status_col;
e1615a19
 	query_vals[n_query_cols].type = DB1_INT;
a3dd1f8f
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = PENDING_STATUS;
 	n_query_cols++;
 
4f692b41
 	result_cols[wuser_col = n_result_cols++] = &str_watcher_username_col;
 	result_cols[wdomain_col = n_result_cols++] = &str_watcher_domain_col;
ea2ce2da
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
a3dd1f8f
 		LM_ERR("sql use table 'watchers_table' failed\n");
 		return -1;
 	}
 
4f692b41
 	if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
 			   n_result_cols, 0, &result)
 			< 0) {
 		LM_ERR("failed to query %.*s table\n", watchers_table.len,
 				watchers_table.s);
a3dd1f8f
 		if(result)
 			pa_dbf.free_result(pa_db, result);
 		return -1;
 	}
ea2ce2da
 
4f692b41
 	if(result == NULL) {
a3dd1f8f
 		LM_ERR("mysql query failed - null result\n");
 		return -1;
 	}
 
4f692b41
 	if(result->n <= 0) {
a3dd1f8f
 		LM_DBG("The query returned no result\n");
 		pa_dbf.free_result(pa_db, result);
 		return 0;
 	}
 
4f692b41
 	for(i = 0; i < result->n; i++) {
a3dd1f8f
 		row = &result->rows[i];
 		row_vals = ROW_VALUES(row);
 
4f692b41
 		wuser.s = (char *)row_vals[wuser_col].val.string_val;
a3dd1f8f
 		wuser.len = strlen(wuser.s);
 
4f692b41
 		wdomain.s = (char *)row_vals[wdomain_col].val.string_val;
a3dd1f8f
 		wdomain.len = strlen(wdomain.s);
 
4f692b41
 		if(uandd_to_uri(wuser, wdomain, &wuri) < 0) {
a3dd1f8f
 			LM_ERR("creating uri from username and domain\n");
 			goto error;
 		}
 
4f692b41
 		if(watcher_found_in_list(watchers, wuri)) {
a3dd1f8f
 			pkg_free(wuri.s);
 			continue;
 		}
ea2ce2da
 
4f692b41
 		w = (watcher_t *)pkg_malloc(sizeof(watcher_t));
 		if(w == NULL) {
4e6c8fe6
 			pkg_free(wuri.s);
a3dd1f8f
 			ERR_MEM(PKG_MEM_STR);
 		}
 		memset(w, 0, sizeof(watcher_t));
 
4f692b41
 		w->status = WAITING_STATUS;
a3dd1f8f
 		w->uri = wuri;
4f692b41
 		w->id.s = (char *)pkg_malloc(w->uri.len * 2 + 1);
 		if(w->id.s == NULL) {
a3dd1f8f
 			pkg_free(w->uri.s);
 			pkg_free(w);
 			ERR_MEM(PKG_MEM_STR);
 		}
 
4f692b41
 		to64frombits((unsigned char *)w->id.s, (const unsigned char *)w->uri.s,
 				w->uri.len);
a3dd1f8f
 		w->id.len = strlen(w->id.s);
4f692b41
 		w->event = event;
a3dd1f8f
 
4f692b41
 		w->next = watchers->next;
 		watchers->next = w;
a3dd1f8f
 	}
 
 	pa_dbf.free_result(pa_db, result);
 	return 0;
 
 error:
 	if(result)
 		pa_dbf.free_result(pa_db, result);
 	return -1;
 }
 
4f692b41
 #define EXTRACT_STRING(strng, chars)                       \
 	do {                                                   \
 		strng.s = (char *)chars;                           \
 		strng.len = strng.s == NULL ? 0 : strlen(strng.s); \
 	} while(0);
8485536f
 
 static int unset_watchers_updated_winfo(str *pres_uri)
 {
 	db_key_t query_cols[3], result_cols[1], update_cols[1];
 	db_val_t query_vals[3], update_vals[1];
 	db_op_t query_ops[2];
 	db1_res_t *result = NULL;
 	int n_query_cols = 0;
0d6e14b1
 	int ret = -1;
8485536f
 	str winfo = str_init("presence.winfo");
34cd2acb
 	db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
8485536f
 
 	/* If this is the only presence.winfo dialog awaiting
 	   update for this presentity reset all of the watchers
 	   updated_winfo fields. */
 
 	query_cols[n_query_cols] = &str_presentity_uri_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val.s = pres_uri->s;
 	query_vals[n_query_cols].val.str_val.len = pres_uri->len;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = winfo;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_updated_col;
 	query_vals[n_query_cols].type = DB1_INT;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = UPDATED_TYPE;
 	n_query_cols++;
 
 	result_cols[0] = &str_id_col;
 
 	update_cols[0] = &str_updated_winfo_col;
 	update_vals[0].type = DB1_INT;
 	update_vals[0].nul = 0;
 	update_vals[0].val.int_val = NO_UPDATE_TYPE;
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	if(query_fn(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols, 1,
 			   0, &result)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		goto error;
 	}
 
4f692b41
 	if(result == NULL) {
e2f65408
 		LM_ERR("bad result\n");
 		goto error;
 	}
8485536f
 
4f692b41
 	if(RES_ROW_N(result) <= 0) {
8485536f
 		query_ops[0] = OP_EQ;
 		query_ops[1] = OP_NEQ;
 
4f692b41
 		if(pa_dbf.update(pa_db, query_cols, query_ops, query_vals, update_cols,
 				   update_vals, 2, 1)
 				< 0) {
8485536f
 			LM_ERR("in sql query\n");
 			goto error;
 		}
 
4f692b41
 		if(pa_dbf.affected_rows)
0d6e14b1
 			ret = pa_dbf.affected_rows(pa_db);
 		else
 			ret = 0;
4f692b41
 	} else
8485536f
 		ret = 0;
 
 error:
4f692b41
 	if(result)
 		pa_dbf.free_result(pa_db, result);
8485536f
 	return ret;
 }
 
0d6e14b1
 static int dialogs_awaiting_update(str *pres_uri, str event)
8485536f
 {
 	db_key_t query_cols[3], result_cols[1];
 	db_val_t query_vals[3];
 	db_op_t query_ops[3];
 	db1_res_t *result = NULL;
 	int n_query_cols = 0;
 	int ret = -1;
34cd2acb
 	db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
8485536f
 
 	query_cols[n_query_cols] = &str_presentity_uri_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val.s = pres_uri->s;
 	query_vals[n_query_cols].val.str_val.len = pres_uri->len;
 	query_ops[n_query_cols] = OP_EQ;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
0d6e14b1
 	query_vals[n_query_cols].val.str_val = event;
8485536f
 	query_ops[n_query_cols] = OP_EQ;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_updated_col;
 	query_vals[n_query_cols].type = DB1_INT;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = NO_UPDATE_TYPE;
 	query_ops[n_query_cols] = OP_NEQ;
 	n_query_cols++;
 
 	result_cols[0] = &str_id_col;
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	if(query_fn(pa_db, query_cols, query_ops, query_vals, result_cols,
 			   n_query_cols, 1, 0, &result)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		goto error;
 	}
 
4f692b41
 	if(result == NULL) {
e2f65408
 		LM_ERR("bad result\n");
 		goto error;
4f692b41
 	} else
0d6e14b1
 		ret = RES_ROW_N(result);
8485536f
 
 error:
4f692b41
 	if(result)
 		pa_dbf.free_result(pa_db, result);
8485536f
 	return ret;
 }
 
 int set_wipeer_subs_updated(str *pres_uri, pres_ev_t *event, int full)
 {
 	db_key_t query_cols[3], result_cols[3], update_cols[2];
 	db_val_t query_vals[3], update_vals[2], *values;
 	db_row_t *rows;
 	db1_res_t *result = NULL;
 	int n_query_cols = 0, n_result_cols = 0, n_update_cols = 0;
 	int callid_col, from_tag_col, to_tag_col;
0d6e14b1
 	int i, ret = -1, count;
8485536f
 	str callid, from_tag, to_tag;
34cd2acb
 	db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
8485536f
 
 	query_cols[n_query_cols] = &str_presentity_uri_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val.s = pres_uri->s;
 	query_vals[n_query_cols].val.str_val.len = pres_uri->len;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = event->name;
 	n_query_cols++;
 
 	result_cols[callid_col = n_result_cols++] = &str_callid_col;
 	result_cols[from_tag_col = n_result_cols++] = &str_from_tag_col;
 	result_cols[to_tag_col = n_result_cols++] = &str_to_tag_col;
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	if(query_fn(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
 			   n_result_cols, 0, &result)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		goto error;
 	}
 
4f692b41
 	if(result == NULL) {
e2f65408
 		LM_ERR("bad result\n");
8485536f
 		goto error;
e2f65408
 	}
8485536f
 
4f692b41
 	if(RES_ROW_N(result) <= 0) {
8485536f
 		ret = 0;
 		goto done;
 	}
 
 	rows = RES_ROWS(result);
0d6e14b1
 	count = RES_ROW_N(result);
4f692b41
 	for(i = 0; i < RES_ROW_N(result); i++) {
8485536f
 		values = ROW_VALUES(&rows[i]);
 
 		EXTRACT_STRING(callid, VAL_STRING(&values[callid_col]));
 		EXTRACT_STRING(from_tag, VAL_STRING(&values[from_tag_col]));
 		EXTRACT_STRING(to_tag, VAL_STRING(&values[to_tag_col]));
 
 		n_query_cols = 0;
 		n_update_cols = 0;
 
 		query_cols[n_query_cols] = &str_callid_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = callid;
 		n_query_cols++;
ea2ce2da
 
8485536f
 		query_cols[n_query_cols] = &str_to_tag_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = to_tag;
 		n_query_cols++;
ea2ce2da
 
8485536f
 		query_cols[n_query_cols] = &str_from_tag_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = from_tag;
 		n_query_cols++;
ea2ce2da
 
8485536f
 		update_cols[n_update_cols] = &str_updated_col;
 		update_vals[n_update_cols].type = DB1_INT;
 		update_vals[n_update_cols].nul = 0;
4b9aa7f1
 		update_vals[n_update_cols].val.int_val =
4f692b41
 				core_case_hash(&callid, &from_tag, 0)
 				% (pres_waitn_time * pres_notifier_poll_rate
 						  * pres_notifier_processes);
8485536f
 		n_update_cols++;
 
4f692b41
 		if(full) {
8485536f
 			update_cols[n_update_cols] = &str_updated_winfo_col;
 			update_vals[n_update_cols].type = DB1_INT;
 			update_vals[n_update_cols].nul = 0;
 			update_vals[n_update_cols].val.int_val = UPDATED_TYPE;
 			n_update_cols++;
 		}
 
4f692b41
 		if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
 				   update_vals, n_query_cols, n_update_cols)
 				< 0) {
8485536f
 			LM_ERR("in sql query\n");
 			goto error;
 		}
0d6e14b1
 
4f692b41
 		if(pa_dbf.affected_rows)
 			if(pa_dbf.affected_rows(pa_db) == 0)
 				count--;
8485536f
 	}
 
ea2ce2da
 	ret = count;
8485536f
 
 done:
 error:
4f692b41
 	if(result)
 		pa_dbf.free_result(pa_db, result);
34cd2acb
 
8485536f
 	return ret;
 }
 
 int set_updated(subs_t *sub)
 {
 	db_key_t query_cols[3], update_cols[1];
 	db_val_t query_vals[3], update_vals[1];
 	int n_query_cols = 0;
 
 	query_cols[n_query_cols] = &str_callid_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = sub->callid;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_to_tag_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = sub->to_tag;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_from_tag_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = sub->from_tag;
 	n_query_cols++;
 
 	update_cols[0] = &str_updated_col;
 	update_vals[0].type = DB1_INT;
 	update_vals[0].nul = 0;
4f692b41
 	update_vals[0].val.int_val = core_case_hash(&sub->callid, &sub->from_tag, 0)
 								 % (pres_waitn_time * pres_notifier_poll_rate
 										   * pres_notifier_processes);
8485536f
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		return -1;
 	}
 
4f692b41
 	if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols, update_vals,
 			   n_query_cols, 1)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		return -1;
 	}
 
4f692b41
 	if(pa_dbf.affected_rows)
0d6e14b1
 		return pa_dbf.affected_rows(pa_db);
 	else
 		return 0;
8485536f
 }
 
 static watcher_t *build_watchers_list(subs_t *sub)
 {
 	db_key_t query_cols[3], result_cols[4];
 	db_val_t query_vals[3], *values;
 	db_row_t *rows;
c24329ed
 	db1_res_t *result = NULL;
8485536f
 	int n_query_cols = 0, n_result_cols = 0;
 	int wuser_col, wdomain_col, callid_col, status_col;
 	int i;
 	subs_t sb;
 	watcher_t *watchers = NULL;
 
4f692b41
 	watchers = (watcher_t *)pkg_malloc(sizeof(watcher_t));
 	if(watchers == NULL) {
8485536f
 		ERR_MEM(PKG_MEM_STR);
 	}
 	memset(watchers, 0, sizeof(watcher_t));
 
 	query_cols[n_query_cols] = &str_presentity_uri_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
4f692b41
 	query_vals[n_query_cols].val.str_val = sub->pres_uri;
8485536f
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = sub->event->wipeer->name;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_updated_winfo_col;
 	query_vals[n_query_cols].type = DB1_INT;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = UPDATED_TYPE;
 	n_query_cols++;
 
 	result_cols[wuser_col = n_result_cols++] = &str_watcher_username_col;
 	result_cols[wdomain_col = n_result_cols++] = &str_watcher_domain_col;
 	result_cols[callid_col = n_result_cols++] = &str_callid_col;
 	result_cols[status_col = n_result_cols++] = &str_status_col;
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
 			   n_result_cols, 0, &result)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		goto error;
 	}
 
4f692b41
 	if(result == NULL) {
e2f65408
 		LM_ERR("bad result\n");
8485536f
 		goto error;
e2f65408
 	}
8485536f
 
4f692b41
 	if(RES_ROW_N(result) <= 0)
8485536f
 		goto done;
 
 	rows = RES_ROWS(result);
4f692b41
 	for(i = 0; i < RES_ROW_N(result); i++) {
8485536f
 		memset(&sb, 0, sizeof(subs_t));
 		values = ROW_VALUES(&rows[i]);
 
 		EXTRACT_STRING(sb.watcher_user, VAL_STRING(&values[wuser_col]));
 		EXTRACT_STRING(sb.watcher_domain, VAL_STRING(&values[wdomain_col]));
 		EXTRACT_STRING(sb.callid, VAL_STRING(&values[callid_col]));
 		sb.status = VAL_INT(&values[status_col]);
 
 		sb.event = sub->event->wipeer;
ea2ce2da
 
4f692b41
 		if(add_watcher_list(&sb, watchers) < 0)
8485536f
 			goto error;
 	}
ea2ce2da
 
8485536f
 done:
 	pa_dbf.free_result(pa_db, result);
 	return watchers;
 
 error:
4f692b41
 	if(result)
 		pa_dbf.free_result(pa_db, result);
8485536f
 	free_watcher_list(watchers);
 	return NULL;
 }
 
0d6e14b1
 static int cleanup_missing_dialog(subs_t *sub)
 {
 	int ret = -1, num_other_watchers = 0;
 
4f692b41
 	if(sub->event->type & WINFO_TYPE) {
 		if(unset_watchers_updated_winfo(&sub->pres_uri) < 0) {
0d6e14b1
 			LM_ERR("resetting updated_winfo flags\n");
 			goto error;
 		}
4f692b41
 	} else if(sub->event->type & PUBL_TYPE) {
 		if((num_other_watchers = dialogs_awaiting_update(
 					&sub->pres_uri, sub->event->name))
 				< 0) {
0d6e14b1
 			LM_ERR("checking watchers\n");
 			goto error;
4f692b41
 		} else if(num_other_watchers == 0) {
 			if(delete_offline_presentities(&sub->pres_uri, sub->event) < 0) {
0d6e14b1
 				LM_ERR("deleting presentity\n");
 				goto error;
 			}
 		}
 	}
 
 	ret = 0;
 
 error:
 	return ret;
 }
 
c6fe62a6
 static int notifier_notify(subs_t *sub, int *updated, int *end_transaction)
8485536f
 {
 	str *nbody = NULL;
 	watcher_t *watchers = NULL;
c6fe62a6
 	int ret = 0, attempt_delete_presentities = 0;
8485536f
 
 	*updated = 0;
 
0d6e14b1
 	/* Terminating dialog NOTIFY */
4f692b41
 	if(sub->expires == 0 || sub->status == TERMINATED_STATUS) {
8485536f
 		sub->status = TERMINATED_STATUS;
 
4f692b41
 		if(sub->event->type & WINFO_TYPE) {
 			if(unset_watchers_updated_winfo(&sub->pres_uri) < 0) {
0d6e14b1
 				LM_WARN("resetting updated_winfo flags\n");
c6fe62a6
 
4f692b41
 				if(pa_dbf.abort_transaction) {
 					if(pa_dbf.abort_transaction(pa_db) < 0) {
c6fe62a6
 						LM_ERR("in abort_transaction\n");
 						goto error;
 					}
 				}
 				*end_transaction = 0;
 
 				/* Make sure this gets tried again next time */
0d6e14b1
 				*updated = 1;
 				goto done;
8485536f
 			}
4f692b41
 		} else {
0d6e14b1
 			str winfo = str_init("presence.winfo");
 			int num_other_watchers, num_winfos;
 
4f692b41
 			if(sub->event->type & PUBL_TYPE) {
 				if((num_other_watchers = dialogs_awaiting_update(
 							&sub->pres_uri, sub->event->name))
 						< 0) {
e2f65408
 					LM_ERR("checking watchers\n");
 					goto error;
4f692b41
 				} else if(num_other_watchers == 0)
e2f65408
 					attempt_delete_presentities = 1;
 			}
 
4f692b41
 			if(sub->event->wipeer) {
 				if((num_winfos = dialogs_awaiting_update(&sub->pres_uri, winfo))
 						< 0) {
0d6e14b1
 					LM_ERR("checking winfos\n");
 					goto error;
 				}
 
4f692b41
 				if(sub->updated_winfo == UPDATED_TYPE && num_winfos > 0) {
8485536f
 					*updated = 1;
 					goto done;
0d6e14b1
 				}
8485536f
 			}
 		}
4f692b41
 	} else /* Non-terminating dialog */
8485536f
 	{
4f692b41
 		if(sub->event->type & WINFO_TYPE) /* presence.winfo dialog */
8485536f
 		{
4f692b41
 			if(sub->updated_winfo == NO_UPDATE_TYPE) {
8485536f
 				/* Partial notify if
 				   updated_winfo == NO_UPDATE_TYPE */
 				int len = 0;
4f692b41
 				char *version_str = int2str(sub->version, &len);
 				if(version_str == NULL) {
8485536f
 					LM_ERR("converting int to str\n");
 					goto error;
 				}
 
 				watchers = build_watchers_list(sub);
4f692b41
 				if(watchers == NULL) {
8485536f
 					LM_ERR("in build_watchers_list\n");
 					goto error;
 				}
 
4f692b41
 				nbody = create_winfo_xml(watchers, version_str, sub->pres_uri,
 						sub->event->wipeer->name, PARTIAL_STATE_FLAG);
 				if(nbody == NULL) {
8485536f
 					LM_ERR("in create_winfo_xml\n");
 					goto error;
 				}
 
4f692b41
 			} else /* Full presence.winfo NOTIFY */
8485536f
 				sub->updated_winfo = NO_UPDATE_TYPE;
5ed96d25
 
4f692b41
 			if(unset_watchers_updated_winfo(&sub->pres_uri) < 0) {
5ed96d25
 				LM_WARN("resetting updated_winfo flags\n");
 
4f692b41
 				if(pa_dbf.abort_transaction) {
 					if(pa_dbf.abort_transaction(pa_db) < 0) {
5ed96d25
 						LM_ERR("in abort_transaction\n");
 						goto error;
 					}
 				}
 				*end_transaction = 0;
 
 				/* Make sure this gets tried again next time */
 				*updated = 1;
 				goto done;
 			}
 
4f692b41
 		} else if(sub->event->type & PUBL_TYPE) {
0d6e14b1
 			int num_other_watchers;
 
4f692b41
 			if((num_other_watchers = dialogs_awaiting_update(
 						&sub->pres_uri, sub->event->name))
 					< 0) {
8485536f
 				LM_ERR("checking watchers\n");
 				goto error;
4f692b41
 			} else if(num_other_watchers == 0)
8485536f
 				attempt_delete_presentities = 1;
fe0e0b89
 		} else if(!pres_send_fast_notify)
8485536f
 			goto done;
 	}
 
4f692b41
 	if(notify(sub, NULL, nbody, 0, 0) < 0) {
8485536f
 		LM_ERR("could not send notify\n");
 		goto error;
 	}
 
0d6e14b1
 	ret = 1;
 
e2f65408
 done:
4f692b41
 	if(attempt_delete_presentities) {
 		if(delete_offline_presentities(&sub->pres_uri, sub->event) < 0) {
8485536f
 			LM_ERR("deleting presentity\n");
 			goto error;
 		}
 	}
 
 	free_notify_body(nbody, sub->event);
 	free_watcher_list(watchers);
 
 	return ret;
c6fe62a6
 
 error:
 	free_notify_body(nbody, sub->event);
 	free_watcher_list(watchers);
 
4f692b41
 	if(pa_dbf.abort_transaction) {
 		if(pa_dbf.abort_transaction(pa_db) < 0)
c6fe62a6
 			LM_ERR("in abort_transaction\n");
 	}
 	*end_transaction = 0;
 
 	return -1;
8485536f
 }
 
 int process_dialogs(int round, int presence_winfo)
 {
a3088218
 	db_key_t query_cols[3], result_cols[20], update_cols[4];
8485536f
 	db_val_t query_vals[3], update_vals[4], *values, *dvalues;
 	db_op_t query_ops[2];
 	db_row_t *rows, *drows;
 	db1_res_t *dialog_list = NULL, *dialog = NULL;
 	int n_query_cols = 0, n_result_cols = 0, n_update_cols = 0;
 	int callid_col, to_tag_col, from_tag_col;
 	int pres_uri_col, tuser_col, tdomain_col, fuser_col, fdomain_col;
 	int wuser_col, wdomain_col, sockinfo_col, lcontact_col, contact_col;
 	int rroute_col, event_id_col, reason_col, event_col, lcseq_col;
 	int rcseq_col, status_col, version_col, updated_winfo_col, expires_col;
a3088218
 	int flags_col, user_agent_col;
8485536f
 	int i, notify_sent = 0, cached_updated_winfo, ret = -1;
0d6e14b1
 	int end_transaction = 0;
8485536f
 	subs_t sub;
 	str ev_sname, winfo = str_init("presence.winfo");
 	int now = (int)time(NULL);
 	int updated = 0;
34cd2acb
 	db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
8485536f
 
 	query_cols[n_query_cols] = &str_updated_col;
 	query_vals[n_query_cols].type = DB1_INT;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.int_val = round;
 	query_ops[n_query_cols] = OP_EQ;
 	n_query_cols++;
 
 	query_cols[n_query_cols] = &str_event_col;
 	query_vals[n_query_cols].type = DB1_STR;
 	query_vals[n_query_cols].nul = 0;
 	query_vals[n_query_cols].val.str_val = winfo;
 	query_ops[n_query_cols] = presence_winfo ? OP_EQ : OP_NEQ;
 	n_query_cols++;
 
0d6e14b1
 	result_cols[pres_uri_col = n_result_cols++] = &str_presentity_uri_col;
8485536f
 	result_cols[callid_col = n_result_cols++] = &str_callid_col;
 	result_cols[to_tag_col = n_result_cols++] = &str_to_tag_col;
 	result_cols[from_tag_col = n_result_cols++] = &str_from_tag_col;
0d6e14b1
 	result_cols[event_col = n_result_cols++] = &str_event_col;
ea2ce2da
 
8485536f
 	update_cols[n_update_cols] = &str_updated_col;
 	update_vals[n_update_cols].type = DB1_INT;
 	update_vals[n_update_cols].nul = 0;
 	update_vals[n_update_cols].val.int_val = NO_UPDATE_TYPE;
 	n_update_cols++;
 
4f692b41
 	if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 		LM_ERR("use table failed\n");
 		goto error;
 	}
 
4f692b41
 	if(pa_dbf.start_transaction) {
fe0e0b89
 		if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
8485536f
 			LM_ERR("in start_transaction\n");
 			goto error;
 		}
 	}
 
 	/* Step 1: Find active_watchers that require notification */
4f692b41
 	if(query_fn(pa_db, query_cols, query_ops, query_vals, result_cols,
 			   n_query_cols, n_result_cols, 0, &dialog_list)
 			< 0) {
8485536f
 		LM_ERR("in sql query\n");
 		goto error;
 	}
4f692b41
 	if(dialog_list == NULL) {
8485536f
 		LM_ERR("bad result\n");
 		goto error;
 	}
 
 	if(dialog_list->n <= 0)
 		goto done;
 
 	/* Step 2: Update the records so they are not notified again */
4f692b41
 	if(pa_dbf.update(pa_db, query_cols, query_ops, query_vals, update_cols,
 			   update_vals, n_query_cols, n_update_cols)
 			< 0) {
8485536f
 		LM_ERR("in sql update\n");
 		goto error;
 	}
 
4f692b41
 	if(pa_dbf.end_transaction) {
 		if(pa_dbf.end_transaction(pa_db) < 0) {
8485536f
 			LM_ERR("in end_transaction\n");
 			goto error;
 		}
 	}
 
 	/* Step 3: Notify each watcher we found */
 	rows = RES_ROWS(dialog_list);
4f692b41
 	for(i = 0; i < RES_ROW_N(dialog_list); i++) {
8485536f
 		n_query_cols = 0;
 		n_result_cols = 0;
 		n_update_cols = 0;
 		memset(&sub, 0, sizeof(subs_t));
 		values = ROW_VALUES(&rows[i]);
 
0d6e14b1
 		EXTRACT_STRING(sub.pres_uri, VAL_STRING(&values[pres_uri_col]));
8485536f
 		EXTRACT_STRING(sub.callid, VAL_STRING(&values[callid_col]));
 		EXTRACT_STRING(sub.to_tag, VAL_STRING(&values[to_tag_col]));
 		EXTRACT_STRING(sub.from_tag, VAL_STRING(&values[from_tag_col]));
0d6e14b1
 		EXTRACT_STRING(ev_sname, VAL_STRING(&values[event_col]));
c6fe62a6
 		sub.event = contains_event(&ev_sname, NULL);
4f692b41
 		if(sub.event == NULL) {
0d6e14b1
 			LM_ERR("event not found and set to NULL\n");
 			goto delete_dialog;
 		}
8485536f
 
 		query_cols[n_query_cols] = &str_callid_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = sub.callid;
 		n_query_cols++;
 
 		query_cols[n_query_cols] = &str_to_tag_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = sub.to_tag;
 		n_query_cols++;
 
 		query_cols[n_query_cols] = &str_from_tag_col;
 		query_vals[n_query_cols].type = DB1_STR;
 		query_vals[n_query_cols].nul = 0;
 		query_vals[n_query_cols].val.str_val = sub.from_tag;
 		n_query_cols++;
 
 		result_cols[tuser_col = n_result_cols++] = &str_to_user_col;
 		result_cols[tdomain_col = n_result_cols++] = &str_to_domain_col;
 		result_cols[fuser_col = n_result_cols++] = &str_from_user_col;
 		result_cols[fdomain_col = n_result_cols++] = &str_from_domain_col;
 		result_cols[wuser_col = n_result_cols++] = &str_watcher_username_col;
 		result_cols[wdomain_col = n_result_cols++] = &str_watcher_domain_col;
 		result_cols[sockinfo_col = n_result_cols++] = &str_socket_info_col;
 		result_cols[lcontact_col = n_result_cols++] = &str_local_contact_col;
 		result_cols[contact_col = n_result_cols++] = &str_contact_col;
 		result_cols[rroute_col = n_result_cols++] = &str_record_route_col;
 		result_cols[event_id_col = n_result_cols++] = &str_event_id_col;
 		result_cols[reason_col = n_result_cols++] = &str_reason_col;
 		result_cols[lcseq_col = n_result_cols++] = &str_local_cseq_col;
 		result_cols[rcseq_col = n_result_cols++] = &str_remote_cseq_col;
 		result_cols[status_col = n_result_cols++] = &str_status_col;
 		result_cols[version_col = n_result_cols++] = &str_version_col;
4f692b41
 		result_cols[updated_winfo_col = n_result_cols++] =
 				&str_updated_winfo_col;
8485536f
 		result_cols[expires_col = n_result_cols++] = &str_expires_col;
a3088218
 		result_cols[flags_col = n_result_cols++] = &str_flags_col;
 		result_cols[user_agent_col = n_result_cols++] = &str_user_agent_col;
8485536f
 
0de5e177
 		/* Need to redo this here as we might have switched to the
 		   presentity table during a previous iteration. */
4f692b41
 		if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
0de5e177
 			LM_ERR("use table failed\n");
 			goto error;
 		}
 
4f692b41
 		if(pa_dbf.start_transaction) {
fe0e0b89
 			if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
8485536f
 				LM_ERR("in start_transaction\n");
 				goto error;
 			}
 		}
0d6e14b1
 		end_transaction = 1;
8485536f
 
4f692b41
 		if(query_fn(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
 				   n_result_cols, 0, &dialog)
 				< 0) {
8485536f
 			LM_ERR("in sql query\n");
 			goto error;
 		}
0d6e14b1
 
4f692b41
 		if(dialog == NULL) {
0d6e14b1
 			LM_ERR("bad result\n");
8485536f
 			goto error;
 		}
0d6e14b1
 
4f692b41
 		if(dialog->n <= 0) {
 			LM_INFO("record not found - this may be observed in multi-server "
 					"systems\n");
 			if(cleanup_missing_dialog(&sub) < 0)
0d6e14b1
 				LM_ERR("cleaning up after missing record\n");
 			goto next_dialog;
 		}
 
4f692b41
 		if(dialog->n > 1) {
 			LM_ERR("multiple records found for %.*s, ci : %.*s, tt : %.*s, ft "
 				   ": %.*s, ev : %.*s\n",
 					sub.pres_uri.len, sub.pres_uri.s, sub.callid.len,
 					sub.callid.s, sub.to_tag.len, sub.to_tag.s,
 					sub.from_tag.len, sub.from_tag.s, ev_sname.len, ev_sname.s);
8485536f
 			goto delete_dialog;
 		}
 
 		drows = RES_ROWS(dialog);
 		dvalues = ROW_VALUES(drows);
 
 		EXTRACT_STRING(sub.to_user, VAL_STRING(&dvalues[tuser_col]));
 		EXTRACT_STRING(sub.to_domain, VAL_STRING(&dvalues[tdomain_col]));
 		EXTRACT_STRING(sub.from_user, VAL_STRING(&dvalues[fuser_col]));
 		EXTRACT_STRING(sub.from_domain, VAL_STRING(&dvalues[fdomain_col]));
 		EXTRACT_STRING(sub.watcher_user, VAL_STRING(&dvalues[wuser_col]));
 		EXTRACT_STRING(sub.watcher_domain, VAL_STRING(&dvalues[wdomain_col]));
 		EXTRACT_STRING(sub.sockinfo_str, VAL_STRING(&dvalues[sockinfo_col]));
 		EXTRACT_STRING(sub.local_contact, VAL_STRING(&dvalues[lcontact_col]));
 		EXTRACT_STRING(sub.contact, VAL_STRING(&dvalues[contact_col]));
 		EXTRACT_STRING(sub.record_route, VAL_STRING(&dvalues[rroute_col]));
 		EXTRACT_STRING(sub.event_id, VAL_STRING(&dvalues[event_id_col]));
 		EXTRACT_STRING(sub.reason, VAL_STRING(&dvalues[reason_col]));
a3088218
 		EXTRACT_STRING(sub.user_agent, VAL_STRING(&dvalues[user_agent_col]));
8485536f
 
 		sub.local_cseq = VAL_INT(&dvalues[lcseq_col]) + 1;
 		sub.remote_cseq = VAL_INT(&dvalues[rcseq_col]);
 		sub.status = VAL_INT(&dvalues[status_col]);
 		sub.version = VAL_INT(&dvalues[version_col]) + 1;
4f692b41
 		cached_updated_winfo = sub.updated_winfo =
 				VAL_INT(&dvalues[updated_winfo_col]);
ea2ce2da
 
fe0e0b89
 		if(VAL_INT(&dvalues[expires_col]) > now + pres_expires_offset)
8485536f
 			sub.expires = VAL_INT(&dvalues[expires_col]) - now;
 		else
 			sub.expires = 0;
a3088218
 		sub.flags = VAL_INT(&dvalues[flags_col]);
8485536f
 
 		sub.updated = round;
 
4f692b41
 		if((notify_sent = notifier_notify(&sub, &updated, &end_transaction))
 				< 0) {
8485536f
 			LM_ERR("sending NOTIFY request\n");
 
4f692b41
 			if(cleanup_missing_dialog(&sub) < 0)
0d6e14b1
 				LM_ERR("cleaning up after error sending NOTIFY"
4f692b41
 					   "request\n");
ea2ce2da
 
0d6e14b1
 			/* remove the dialog and continue */
8485536f
 			goto delete_dialog;
 		}
 
4f692b41
 		if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
8485536f
 			LM_ERR("use table failed\n");
 			goto error;
 		}
 
4f692b41
 		if((sub.expires > 0 && sub.status != TERMINATED_STATUS) || updated) {
 			if(sub.updated_winfo != cached_updated_winfo) {
8485536f
 				update_cols[n_update_cols] = &str_updated_winfo_col;
 				update_vals[n_update_cols].type = DB1_INT;
 				update_vals[n_update_cols].nul = 0;
 				update_vals[n_update_cols].val.int_val = sub.updated_winfo;
 				n_update_cols++;
 			}
 
4f692b41
 			if(updated) {
8485536f
 				update_cols[n_update_cols] = &str_updated_col;
 				update_vals[n_update_cols].type = DB1_INT;
 				update_vals[n_update_cols].nul = 0;
 				update_vals[n_update_cols].val.int_val = round;
 				n_update_cols++;
 			}
 
4f692b41
 			if(notify_sent) {
8485536f
 				update_cols[n_update_cols] = &str_local_cseq_col;
 				update_vals[n_update_cols].type = DB1_INT;
 				update_vals[n_update_cols].nul = 0;
 				update_vals[n_update_cols].val.int_val = sub.local_cseq;
 				n_update_cols++;
 
 				update_cols[n_update_cols] = &str_version_col;
 				update_vals[n_update_cols].type = DB1_INT;
 				update_vals[n_update_cols].nul = 0;
 				update_vals[n_update_cols].val.int_val = sub.version;
 				n_update_cols++;
 			}
 
4f692b41
 			if(n_update_cols > 0) {
 				if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
 						   update_vals, n_query_cols, n_update_cols)
 						< 0) {
8485536f
 					LM_ERR("in sql update\n");
 					goto error;
 				}
 			}
 
4f692b41
 		} else if(notify_sent) {
 		delete_dialog:
 			if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
0d6e14b1
 				LM_ERR("use table failed\n");
 				goto error;
 			}
8485536f
 
4f692b41
 			if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)
 					< 0) {
0d6e14b1
 				LM_ERR("in sql delete");
 				goto error;
 			}
8485536f
 		}
 
4f692b41
 	next_dialog:
 		if(pa_dbf.end_transaction && end_transaction) {
 			if(pa_dbf.end_transaction(pa_db) < 0) {
8485536f
 				LM_ERR("in end_transaction\n");
 				goto error;
 			}
 		}
 
 		pa_dbf.free_result(pa_db, dialog);
 		dialog = NULL;
 	}
 
 done:
 	ret = 0;
 error:
4f692b41
 	if(dialog_list)
 		pa_dbf.free_result(pa_db, dialog_list);
 	if(dialog)
 		pa_dbf.free_result(pa_db, dialog);
8485536f
 
4f692b41
 	if(pa_dbf.abort_transaction) {
 		if(pa_dbf.abort_transaction(pa_db) < 0)
8485536f
 			LM_ERR("in abort_transaction\n");
 	}
 
 	return ret;
 }
 
 void pres_timer_send_notify(unsigned int ticks, void *param)
 {
4f692b41
 	int process_num = *((int *)param);
 	int round =
 			subset + (pres_waitn_time * pres_notifier_poll_rate * process_num);
8485536f
 
4f692b41
 	if(++subset > (pres_waitn_time * pres_notifier_poll_rate) - 1)
d1cda7ca
 		subset = 0;
 
4f692b41
 	if(process_dialogs(round, 0) < 0) {
8485536f
 		LM_ERR("Handling non presence.winfo dialogs\n");
 		return;
 	}
4f692b41
 	if(process_dialogs(round, 1) < 0) {
8485536f
 		LM_ERR("Handling presence.winfo dialogs\n");
 		return;
 	}
 }