obsolete/pa/subscribe.c
fdeceea5
 /*
  * Presence Agent, subscribe handling
  *
  * $Id$
  *
95072403
  * Copyright (C) 2001-2003 FhG Fokus
fdeceea5
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
bdc57f2f
  *
  * History:
  * ---------
22856c99
  * 2003-02-29 scratchpad compatibility abandoned
bdc57f2f
  * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
fdeceea5
  */
 
cf76b1ce
 #include <string.h>
026ba2fd
 #include <limits.h>
cf76b1ce
 #include "../../str.h"
 #include "../../dprint.h"
 #include "../../mem/mem.h"
c22504bf
 #include "../../parser/parse_uri.h"
cf76b1ce
 #include "../../parser/parse_from.h"
9470206e
 #include "../../parser/parse_expires.h"
cf76b1ce
 #include "../../parser/parse_event.h"
4984a9b5
 #include "../../data_lump_rpl.h"
cf76b1ce
 #include "presentity.h"
9470206e
 #include "watcher.h"
c22504bf
 #include "notify.h"
9470206e
 #include "paerrno.h"
 #include "pdomain.h"
cf76b1ce
 #include "pa_mod.h"
 #include "ptime.h"
 #include "reply.h"
9470206e
 #include "subscribe.h"
541e1786
 #include "auth.h"
284e5638
 #include <cds/sstr.h>
 #include <cds/msg_queue.h>
3e804d75
 #include <cds/logger.h>
f7372307
 #include <cds/sip_utils.h>
6239ba21
 #include <presence/utils.h>
626094a5
 #include "offline_winfo.h"
f7372307
 #include "mimetypes.h"
 
 #include <string.h>
 #include "../../mem/shm_mem.h"
 #include "../../dprint.h"
 #include "../../globals.h"
 #include "../../md5.h"
 #include "../../crc.h"
 #include "../../ip_addr.h"
 #include "../../socket_info.h"
7a7f1a7b
 #include "../../modules/tm/ut.h"
 #include "../../modules/tm/h_table.h"
 #include "../../modules/tm/t_hooks.h"
 #include "../../modules/tm/t_funcs.h"
 #include "../../modules/tm/t_msgbuilder.h"
 #include "../../modules/tm/callid.h"
 #include "../../modules/tm/uac.h"
9470206e
 
 #define DOCUMENT_TYPE "application/cpim-pidf+xml"
 #define DOCUMENT_TYPE_L (sizeof(DOCUMENT_TYPE) - 1)
 
cf76b1ce
 /*
  * Extract plain uri -- return URI without parameters
b37fbbd0
  * The uri will be in form username@domain
  *
cf76b1ce
  */
b37fbbd0
 static int extract_plain_uri(str* _uri)
cf76b1ce
 {
 	struct sip_uri puri;
e7d99a09
 	int res = 0;
cf76b1ce
 
 	if (parse_uri(_uri->s, _uri->len, &puri) < 0) {
 		paerrno = PA_URI_PARSE;
 		LOG(L_ERR, "extract_plain_uri(): Error while parsing URI\n");
 		return -1;
 	}
 	
2393d0b6
 	/* _uri->s = puri.user.s;
4984a9b5
 	if ((!_uri->s) || (puri.user.len < 1)) {
 		_uri->s = puri.host.s;
 		_uri->len = puri.host.len;
 		return -1;
2393d0b6
 	}*/
e7d99a09
 	if (puri.user.len < 1) {
 		res = -1; /* it is uri without username ! */
 	}
cf76b1ce
 	_uri->len = puri.host.s + puri.host.len - _uri->s;
e7d99a09
 	return res;
cf76b1ce
 }
 
 /*
  * Get presentity URI, which is stored in R-URI
  */
6a00f95d
 int get_pres_uri(struct sip_msg* _m, str* _puri)
fdeceea5
 {
cf76b1ce
 	if (_m->new_uri.s) {
 		_puri->s = _m->new_uri.s;
 		_puri->len = _m->new_uri.len;
 	} else {
 		_puri->s = _m->first_line.u.request.uri.s;
 		_puri->len = _m->first_line.u.request.uri.len;
 	}
284e5638
 	LOG(L_DBG, "get_pres_uri: _puri=%.*s\n", _puri->len, _puri->s);
4984a9b5
 
cf76b1ce
 	if (extract_plain_uri(_puri) < 0) {
4984a9b5
 		_puri->s = get_to(_m)->uri.s;
 		_puri->len = get_to(_m)->uri.len;
284e5638
 		LOG(L_DBG, "get_pres_uri(2): _puri=%.*s\n", _puri->len, _puri->s);
4984a9b5
 	
 		if (extract_plain_uri(_puri) < 0) {
 			LOG(L_ERR, "get_pres_uri(): Error while extracting plain URI\n");
 			return -1;
 		}
fdeceea5
 	}
 
cf76b1ce
 	return 0;
fdeceea5
 }
 
 
04847d67
 static int get_watch_uri(struct sip_msg* _m, str* _wuri, str *_dn)
fdeceea5
 {
cf76b1ce
 	_wuri->s = get_from(_m)->uri.s;
 	_wuri->len = get_from(_m)->uri.len;
04847d67
 	_dn->s = get_from(_m)->body.s;
 	_dn->len = get_from(_m)->body.len;
fdeceea5
 
cf76b1ce
 	if (extract_plain_uri(_wuri) < 0) {
 		LOG(L_ERR, "get_watch_uri(): Error while extracting plain URI\n");
fdeceea5
 		return -1;
 	}
cf76b1ce
 	
 	return 0;
 }
fdeceea5
 
4984a9b5
 static int get_dlg_id(struct sip_msg *_m, dlg_id_t *dst)
 {
 	if (!dst) return -1;
 	
 	memset(dst, 0, sizeof(*dst));
 	if (_m->to) dst->loc_tag = ((struct to_body*)_m->to->parsed)->tag_value;
 	if (_m->from) dst->rem_tag = ((struct to_body*)_m->from->parsed)->tag_value;
 	if (_m->callid) dst->call_id = _m->callid->body;
 	
 	return 0;
 }
 
f7372307
 static time_t get_expires(struct sip_msg *_m)
 {
 	time_t e;
 	
 	if (_m->expires) e = ((exp_body_t*)_m->expires->parsed)->val;
 	else e = default_expires;
 	if (e > max_subscription_expiration) 
 		e = max_subscription_expiration;
 	return e;
 }
 
cf76b1ce
 /*
  * Parse all header fields that will be needed
  * to handle a SUBSCRIBE request
  */
1e406260
 static int parse_hfs(struct sip_msg* _m, int accept_header_required)
cf76b1ce
 {
0ed42e71
 	int rc = 0;
1666e93e
 	struct hdr_field *acc;
 	
 	/* EOH instead HDR_FROM_F | HDR_EVENT_F | HDR_EXPIRES_F | HDR_ACCEPT_F  
 	 * because we need all Accept headers */
7d5d026c
 	if ( (rc = parse_headers(_m, HDR_EOH_F, 0)) == -1) {
cf76b1ce
 		paerrno = PA_PARSE_ERR;
0ed42e71
 		LOG(L_ERR, "parse_hfs(): Error while parsing headers: rc=%d\n", rc);
cf76b1ce
 		return -1;
fdeceea5
 	}
 
7d5d026c
 	if (!_m->from) {
 		ERR("From header missing\n");
 		return -1;
 	}
 	
cf76b1ce
 	if (parse_from_header(_m) < 0) {
 		paerrno = PA_FROM_ERR;
 		LOG(L_ERR, "parse_hfs(): From malformed or missing\n");
fdeceea5
 		return -6;
 	}
 
 	if (_m->event) {
 		if (parse_event(_m->event) < 0) {
f7372307
 			/* can not parse Event header */
fdeceea5
 			paerrno = PA_EVENT_PARSE;
cf76b1ce
 			LOG(L_ERR, "parse_hfs(): Error while parsing Event header field\n");
fdeceea5
 			return -8;
 		}
 	}
1666e93e
 	else { 
f7372307
 		/* no Event header -> bad message */
1666e93e
 		paerrno = PA_EVENT_PARSE;
 		LOG(L_ERR, "parse_hfs(): Error while parsing Event header field\n");
 		return -8;
 	}
fdeceea5
 
 	if (_m->expires) {
 		if (parse_expires(_m->expires) < 0) {
 			paerrno = PA_EXPIRES_PARSE;
cf76b1ce
 			LOG(L_ERR, "parse_hfs(): Error while parsing Expires header field\n");
fdeceea5
 			return -9;
 		}
 	}
 
0ed42e71
 	/* now look for Accept header */
1666e93e
 	acc = _m->accept;
 	if (accept_header_required && (!acc)) {
9009f7db
 		LOG(L_ERR, "no accept header\n");
348b543f
 		return -11;
cf76b1ce
 	}
1666e93e
 	
 	while (acc) { /* parse all accept headers */
 		if (acc->type == HDR_ACCEPT_T) {
e5dd5e9c
 			DBG("parsing accept header: %.*s\n", FMT_STR(acc->body));
1666e93e
 			if (parse_accept_body(acc) < 0) {
 				paerrno = PA_ACCEPT_PARSE;
 				LOG(L_ERR, "parse_hfs(): Error while parsing Accept header field\n");
 				return -10;
 			}
 		}
 		acc = acc->next;
 	}
fdeceea5
 
 	return 0;
 }
 
f7372307
 /* returns 0 if package supported by PA */
 static inline int verify_event_package(int et)
1666e93e
 {
f7372307
 	switch (et) {
 		case EVENT_PRESENCE: return 0;
 		case EVENT_PRESENCE_WINFO: 
 			if (watcherinfo_notify) return 0;
 			else return -1;
 		default: return -1;
1666e93e
 	}
 }
 
f7372307
 /* get_event MUST be parsed when calling get event -> done by parse_hfs! */
 #define get_event(_m) ((event_t*)(_m->event->parsed))->parsed
fdeceea5
 
cf76b1ce
 /*
  * Check if a message received has been constructed properly
  */
5d58dfb2
 static int check_message(struct sip_msg* _m)
fdeceea5
 {
1666e93e
 	int eventtype = 0;
 	int *accepts_mimes = NULL;
 	event_mimetypes_t *em;
 	struct hdr_field *acc;
 
 	if ((!_m->event) || (!_m->event->parsed)) {
 		paerrno = PA_EXPIRES_PARSE;
5d58dfb2
 		ERR("Event header field not found\n");
1666e93e
 		return -1; /* should be verified in parse_hfs before */
 	}
 
 	/* event package verification */
f7372307
 	eventtype = get_event(_m);
 	
 	if (verify_event_package(eventtype) != 0) {
 		INFO("Unsupported event package\n");
 		paerrno = PA_EVENT_UNSUPP;
 		return -1;
 	}
 
1666e93e
 	em = find_event_mimetypes(eventtype);
 	if (em) 
 		if (em->event_type == -1) em = NULL;
 	if (!em) {
 		paerrno = PA_EVENT_UNSUPP;
5d58dfb2
 		ERR("Unsupported event package\n");
1666e93e
 		return -1;
 	}
 
 	acc = _m->accept;
 	if (!acc) return 0; /* default will be used */
 	
 	while (acc) { /* go through all Accept headers */
 		if (acc->type == HDR_ACCEPT_T) {
 			/* it MUST be parsed from parse_hdr !!! */
 			accepts_mimes = acc->parsed;
 			if (check_mime_types(accepts_mimes, em) == 0) return 0;
 			
348b543f
 			/* else, none of the mimetypes accepted are generated for this event package */
5d58dfb2
 			INFO("Accepts %.*s not valid for event package et=%.*s\n",
1666e93e
 				acc->body.len, acc->body.s, _m->event->body.len, _m->event->body.s);
fdeceea5
 		}
1666e93e
 		acc = acc->next;
fdeceea5
 	}
79e1c32d
 	paerrno = PA_WRONG_ACCEPTS;
5d58dfb2
 	ERR("no satisfactory document type found\n");
1666e93e
 	return -1;
fdeceea5
 }
 
f7372307
 static int create_watcher(struct sip_msg* _m, struct watcher** _w)
fdeceea5
 {
cf76b1ce
 	dlg_t* dialog;
03f6db11
 	str server_contact = STR_NULL;
541e1786
 	int acc = 0;
cf76b1ce
 	str watch_uri;
04847d67
 	str watch_dn;
f7372307
 	int et;
 	time_t expires;
 	
 	et = get_event(_m);	
 	expires = get_expires(_m);
 	if (expires) expires += act_time;
541e1786
 	
 	if (get_watch_uri(_m, &watch_uri, &watch_dn) < 0) {
 		paerrno = PA_URI_PARSE;
f7372307
 		ERR("Error while extracting watcher URI\n");
541e1786
 		return -1;
 	}
 	acc = get_preferred_event_mimetype(_m, et);
 	if (tmb.new_dlg_uas(_m, 200, &dialog) < 0) {
 		paerrno = PA_DIALOG_ERR;
f7372307
 		ERR("Error while creating dialog state\n");
541e1786
 		return -4;
 	}
 	
6239ba21
 	if (extract_server_contact(_m, &server_contact, 1) != 0) {
541e1786
 		paerrno = PA_DIALOG_ERR;
f7372307
 		ERR("Error while extracting server contact\n");
541e1786
 		return -3;
 	}
 
5d58dfb2
 	if (new_watcher_no_wb(&watch_uri, expires, et, acc, dialog, 
 				&watch_dn, &server_contact, NULL, _w) < 0) {
f7372307
 		ERR("Error while creating watcher\n");
541e1786
 		tmb.free_dlg(dialog);
2a385f88
 		if (server_contact.s) mem_free(server_contact.s);
541e1786
 		paerrno = PA_NO_MEMORY;
 		return -5;
 	}
2a385f88
 	if (server_contact.s) mem_free(server_contact.s);
541e1786
 	
f7372307
 	(*_w)->flags |= WFLAG_SUBSCRIPTION_CHANGED;
 	
 	return 0;
 }
541e1786
 
fdeceea5
 
f7372307
 static inline int add_rpl_expires(struct sip_msg *_m, watcher_t *w)
541e1786
 {
f7372307
 	int i = 0;
 	char tmp[64];
 	
 	/* add expires header field into response */
 	if (w) i = w->expires - act_time;
 	if (i < 0) i = 0;
 	sprintf(tmp, "Expires: %d\r\n", i);
 	if (!add_lump_rpl(_m, tmp, strlen(tmp), LUMP_RPL_HDR)) {
 		ERR("Can't add Expires header to the response\n");
fdeceea5
 		return -1;
 	}
f7372307
 	
cf76b1ce
 	return 0;
fdeceea5
 }
 
f7372307
 int handle_renewal_subscription(struct sip_msg* _m, struct pdomain *d)
fdeceea5
 {
f7372307
 	struct presentity *p = NULL;
 	struct watcher* w = NULL;
 	str uid = STR_NULL;
4984a9b5
 	dlg_id_t dlg_id;
f7372307
 	int et, e;
 	
5d58dfb2
 	if (get_presentity_uid(&uid, _m) < 0) {
f7372307
 		ERR("Error while extracting presentity UID\n");
 		paerrno = PA_INTERNAL_ERROR;
 		goto err;
 	}	
fdeceea5
 
f7372307
 	/* needed to find watcher (better to set outside of crit. sect. due to
 	 * better performance) */
 	et = get_event(_m);	
 	get_dlg_id(_m, &dlg_id);
541e1786
 	
f7372307
 	lock_pdomain(d);
 		
 	if (find_presentity_uid(d, &uid, &p) != 0) { 
 		/* presentity not found */
 		INFO("resubscription to nonexisting presentity %.*s\n", FMT_STR(uid));
 		paerrno = PA_SUBSCRIPTION_NOT_EXISTS;
 		goto err2;
fdeceea5
 	}
f7372307
 	
 	if (find_watcher_dlg(p, &dlg_id, et, &w) != 0) {
 		/* watcher not found */
 		INFO("resubscription for nonexisting watcher\n");
 		paerrno = PA_SUBSCRIPTION_NOT_EXISTS;
 		goto err2;
9470206e
 	}
541e1786
 	
f7372307
 	e = get_expires(_m);
 	if (e) e += act_time;
 	
 	update_watcher(p, w, e, _m);
 	set_last_subscription_status(w->status);	
 	add_rpl_expires(_m, w);
 	if (send_reply(_m) >= 0) {
 		/* we have successfully sent the response */
 		if (send_notify(p, w) >= 0) {		
 			w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED; /* notified */
 			
 			/* remove terminated watcher otherwise he will 
 			 * receive another NOTIFY generated from timer_pdomain */
5d58dfb2
 			if (is_watcher_terminated(w)) {
 				remove_watcher(p, w);
 				free_watcher(w);
 			}
f7372307
 		} 
 	}
 	else {
 		ERR("Error while sending reply\n");
 	}
4984a9b5
 	
f7372307
 	unlock_pdomain(d);
541e1786
 	
f7372307
 	return 1;
fdeceea5
 
f7372307
 err2:
 	unlock_pdomain(d);
 	
 err:
 	set_last_subscription_status(WS_REJECTED);
 	
 	if (send_reply(_m) < 0) ERR("Error while sending reply\n");
 	return -1;
fdeceea5
 }
 
f7372307
 presentity_t *get_presentity(struct sip_msg *_m, struct pdomain *d, int allow_creation)
1e406260
 {
f7372307
 	str p_uri, uid;
 	presentity_t *p = NULL;
 	xcap_query_params_t xcap_params;
 /*	presence_rules_t *auth_rules = NULL;*/
1e406260
 
f7372307
 	if (get_presentity_uid(&uid, _m) < 0) {
 		ERR("Error while extracting presentity UID\n");
 		return NULL;
1e406260
 	}
 	
f7372307
 	if (find_presentity_uid(d, &uid, &p) > 0)  {
 		if (allow_creation) {
 			if (get_pres_uri(_m, &p_uri) < 0) {
 				ERR("Error while extracting presentity URI\n");
 			}
 			else {
 				/* presentity not found -> create new presentity */
 				memset(&xcap_params, 0, sizeof(xcap_params));
 				if (fill_xcap_params) fill_xcap_params(_m, &xcap_params);
 				if (new_presentity(d, &p_uri, &uid, &xcap_params, &p) < 0)
 					ERR("Error while creating new presentity\n");
 			}
 		}
1e406260
 	}
f7372307
 	return p;
1e406260
 }
 
f7372307
 int handle_new_subscription(struct sip_msg* _m, struct pdomain *d)
1e406260
 {
f7372307
 	struct presentity *p;
 	struct watcher* w;
 	struct retr_buf *req;
 	int is_terminated;
1e406260
 	
f7372307
 	if (create_watcher(_m, &w) < 0) {
 		ERR("can't create watcher\n");
 		goto err;
 	}
1e406260
 
f7372307
 	lock_pdomain(d);
49447807
 
f7372307
 	p = get_presentity(_m, d, 1);
 	if (!p) goto err3;
1e406260
 	
f7372307
 	/* authorize watcher */
 	w->status = authorize_watcher(p, w);
 										   
 	switch (w->status) {
 		case WS_REJECTED:
 			unlock_pdomain(d);
 			free_watcher(w);
 			paerrno = PA_SUBSCRIPTION_REJECTED;
 			INFO("watcher rejected\n");
 			goto err;
 		case WS_PENDING:
 		case WS_PENDING_TERMINATED:
 			paerrno = PA_OK_WAITING_FOR_AUTH;
 		default:
 			break;
 	}
 	if (w->expires <= act_time) {
 		set_watcher_terminated_status(w);
 		is_terminated = 1;
2df90abe
 	}
 	else {
f7372307
 		is_terminated = 0;	
 
5d58dfb2
 		if (append_watcher(p, w, 1) < 0) {
f7372307
 			ERR("can't add watcher\n");
 			goto err3;
 		}
 	}
 	
 	if (prepare_notify(&req, p, w) < 0) {
 		ERR("can't send notify\n");
2e472c6b
 		goto err4;
2df90abe
 	}
 
f7372307
 	set_last_subscription_status(w->status);
 	add_rpl_expires(_m, w);
626094a5
 	
f7372307
 	unlock_pdomain(d);
2df90abe
 
f7372307
 	send_reply(_m); 
2df90abe
 	
f7372307
 	if (req) {
 		tmb.send_prepared_request(req);
 		w->flags &= ~WFLAG_SUBSCRIPTION_CHANGED; /* notified */
 		if (is_terminated) {
 			free_watcher(w);
 			w = NULL;
 		} 
2df90abe
 	}
f7372307
 
 	return 1;
2e472c6b
 	
 err4:
 	remove_watcher(p, w);
f7372307
 
 err3:
 	unlock_pdomain(d);
 	free_watcher(w);
 	paerrno = PA_INTERNAL_ERROR;
 	
 err:
 	set_last_subscription_status(WS_REJECTED);
 	
 	if (paerrno == PA_OK) paerrno = PA_INTERNAL_ERROR;
 	if (send_reply(_m) < 0) ERR("Error while sending reply\n");
 	return -1;
2df90abe
 }
 
fdeceea5
 /*
  * Handle a subscribe Request
  */
cf76b1ce
 int handle_subscription(struct sip_msg* _m, char* _domain, char* _s2)
fdeceea5
 {
f7372307
 	int res;
928b6ec0
 	PROF_START_DECL(pa_response_generation)
 
 	PROF_START(pa_handle_subscription)
 
cf76b1ce
 	get_act_time();
fdeceea5
 	paerrno = PA_OK;
 
e8a6b0f7
 	if (parse_hfs(_m, 0) < 0) {
e5dd5e9c
 		ERR("Error while parsing message header\n");
fdeceea5
 		goto error;
 	}
 
 	if (check_message(_m) < 0) {
e5dd5e9c
 		ERR("Error while checking message\n");
fdeceea5
 		goto error;
 	}
 
f7372307
 	if (has_to_tag(_m)) 
 		res = handle_renewal_subscription(_m, (struct pdomain*)_domain);
 	else
 		res = handle_new_subscription(_m, (struct pdomain*)_domain);
fdeceea5
 
928b6ec0
 	PROF_STOP(pa_handle_subscription)
f7372307
 	return res;
fdeceea5
 	
  error:
928b6ec0
 	INFO("handle_subscription about to send_reply and return -2\n");
fdeceea5
 	send_reply(_m);
626094a5
 	set_last_subscription_status(WS_REJECTED);
928b6ec0
 	PROF_STOP(pa_handle_subscription)
cf76b1ce
 	return -1;
 }