2 * Copyright (C) 2006 Voice Sistem S.R.L.
4 * This file is part of Kamailio, a free SIP server.
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * \brief Kamailio presence module :: Support for PUBLISH handling
31 #include "../../core/ut.h"
32 #include "../../core/str.h"
33 #include "../../core/parser/parse_to.h"
34 #include "../../core/parser/parse_uri.h"
35 #include "../../core/parser/parse_expires.h"
36 #include "../../core/parser/parse_event.h"
37 #include "../../core/parser/parse_content.h"
38 #include "../../core/lock_ops.h"
39 #include "../../core/hashes.h"
40 #include "../../core/strutils.h"
41 #include "../../core/mod_fix.h"
42 #include "../../lib/srdb1/db.h"
45 #include "utils_func.h"
47 #include "presentity.h"
49 extern gen_lock_set_t *set;
51 static str pu_400a_rpl = str_init("Bad request");
52 static str pu_400b_rpl = str_init("Invalid request");
53 static str pu_500_rpl = str_init("Server Internal Error");
54 static str pu_489_rpl = str_init("Bad Event");
62 void msg_presentity_clean(unsigned int ticks, void *param)
64 db_key_t db_keys[2], result_cols[4];
65 db_val_t db_vals[2], *values;
67 db1_res_t *result = NULL;
69 int n_db_cols = 0, n_result_cols = 0;
70 int event_col, etag_col, user_col, domain_col;
71 int i = 0, num_watchers = 0;
73 str uri = {0, 0}, event, *rules_doc = NULL;
76 LM_DBG("cleaning expired presentity information\n");
77 if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
78 LM_ERR("in use_table\n");
82 db_keys[n_db_cols] = &str_expires_col;
83 db_ops[n_db_cols] = OP_LT;
84 db_vals[n_db_cols].type = DB1_INT;
85 db_vals[n_db_cols].nul = 0;
86 db_vals[n_db_cols].val.int_val = (int)time(NULL);
89 db_keys[n_db_cols] = &str_expires_col;
90 db_ops[n_db_cols] = OP_GT;
91 db_vals[n_db_cols].type = DB1_INT;
92 db_vals[n_db_cols].nul = 0;
93 db_vals[n_db_cols].val.int_val = 0;
96 result_cols[user_col = n_result_cols++] = &str_username_col;
97 result_cols[domain_col = n_result_cols++] = &str_domain_col;
98 result_cols[etag_col = n_result_cols++] = &str_etag_col;
99 result_cols[event_col = n_result_cols++] = &str_event_col;
101 query_str = str_username_col;
102 if(db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, db_keys, db_ops, db_vals,
103 result_cols, n_db_cols, n_result_cols, &query_str, &result)
105 LM_ERR("failed to query database for expired messages\n");
110 LM_ERR("bad result\n");
114 LM_DBG("found n= %d expires messages\n ", result->n);
117 rows = RES_ROWS(result);
119 for(i = 0; i < RES_ROW_N(result); i++) {
120 values = ROW_VALUES(&rows[i]);
121 memset(&pres, 0, sizeof(presentity_t));
123 pres.user.s = (char *)VAL_STRING(&values[user_col]);
124 pres.user.len = strlen(pres.user.s);
125 pres.domain.s = (char *)VAL_STRING(&values[domain_col]);
126 pres.domain.len = strlen(pres.domain.s);
127 pres.etag.s = (char *)VAL_STRING(&values[etag_col]);
128 pres.etag.len = strlen(pres.etag.s);
129 event.s = (char *)VAL_STRING(&values[event_col]);
130 event.len = strlen(event.s);
131 pres.event = contains_event(&event, NULL);
132 if(pres.event == NULL || pres.event->evp == NULL) {
133 LM_ERR("event not found\n");
137 if(uandd_to_uri(pres.user, pres.domain, &uri) < 0) {
138 LM_ERR("constructing uri\n");
142 /* delete from hash table */
143 if(publ_cache_mode==PS_PCACHE_HYBRID
144 && delete_phtable(&uri, pres.event->evp->type) < 0) {
145 LM_ERR("deleting from presentity hash table\n");
149 LM_DBG("found expired publish for [user]=%.*s [domanin]=%.*s\n",
150 pres.user.len, pres.user.s, pres.domain.len, pres.domain.s);
152 if(pres_force_delete == 1) {
153 if(delete_presentity(&pres, NULL) < 0) {
154 LM_ERR("Deleting presentity\n");
157 } else if(pres_notifier_processes > 0) {
158 if(pa_dbf.start_transaction) {
159 if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
160 LM_ERR("in start_transaction\n");
164 if((num_watchers = publ_notify_notifier(uri, pres.event)) < 0) {
165 LM_ERR("Updating watcher records\n");
166 if(pa_dbf.abort_transaction) {
167 if(pa_dbf.abort_transaction(pa_db) < 0)
168 LM_ERR("in abort_transaction\n");
173 if(num_watchers > 0) {
174 if(mark_presentity_for_delete(&pres, NULL) < 0) {
175 LM_ERR("Marking presentity\n");
176 if(pa_dbf.abort_transaction) {
177 if(pa_dbf.abort_transaction(pa_db) < 0)
178 LM_ERR("in abort_transaction\n");
183 if(delete_presentity(&pres, NULL) < 0) {
184 LM_ERR("Deleting presentity\n");
188 if(pa_dbf.end_transaction) {
189 if(pa_dbf.end_transaction(pa_db) < 0) {
190 LM_ERR("in end_transaction\n");
195 if(pres.event->get_rules_doc
196 && pres.event->get_rules_doc(
197 &pres.user, &pres.domain, &rules_doc)
199 LM_ERR("getting rules doc\n");
202 if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc) < 0) {
203 LM_ERR("sending Notify request\n");
208 pkg_free(rules_doc->s);
217 } while(db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
218 && RES_ROW_N(result) > 0);
220 pa_dbf.free_result(pa_db, result);
223 if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
224 LM_ERR("in use_table\n");
228 if(pres_notifier_processes == 0) {
230 if(pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, n_db_cols) < 0)
231 LM_ERR("failed to delete expired records from DB\n");
238 pa_dbf.free_result(pa_db, result);
243 pkg_free(rules_doc->s);
251 * PUBLISH request handling
254 int ki_handle_publish_uri(struct sip_msg *msg, str *sender_uri)
259 presentity_t *presentity = 0;
260 struct hdr_field *hdr;
261 int found = 0, etag_gen = 0;
264 static char buf[256];
266 pres_ev_t *event = NULL;
275 reply_str = pu_500_rpl;
278 if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
279 LM_ERR("parsing headers\n");
281 reply_str = pu_400a_rpl;
284 memset(&body, 0, sizeof(str));
286 /* inspecting the Event header field */
288 if(msg->event && msg->event->body.len > 0) {
289 if(!msg->event->parsed && (parse_event(msg->event) < 0)) {
290 LM_ERR("cannot parse Event header\n");
292 reply_str = pu_400a_rpl;
296 goto unsupported_event;
298 /* search event in the list */
299 event = search_event((event_t *)msg->event->parsed);
301 goto unsupported_event;
304 /* examine the SIP-If-Match header field */
307 if(cmp_hdrname_strzn(&hdr->name, "SIP-If-Match", 12) == 0) {
314 LM_DBG("SIP-If-Match header not found\n");
315 etag.s = generate_ETag(0);
317 LM_ERR("when generating etag\n");
320 etag.len = (strlen(etag.s));
322 LM_DBG("new etag = %.*s \n", etag.len, etag.s);
324 LM_DBG("SIP-If-Match header found\n");
325 etag.s = (char *)pkg_malloc((hdr->body.len + 1) * sizeof(char));
327 ERR_MEM(PKG_MEM_STR);
329 memcpy(etag.s, hdr->body.s, hdr->body.len);
330 etag.len = hdr->body.len;
331 etag.s[etag.len] = '\0';
332 LM_DBG("existing etag = %.*s \n", etag.len, etag.s);
335 /* examine the expire header field */
336 if(msg->expires && msg->expires->body.len > 0) {
337 if(!msg->expires->parsed && (parse_expires(msg->expires) < 0)) {
338 LM_ERR("cannot parse Expires header\n");
341 lexpire = ((exp_body_t *)msg->expires->parsed)->val;
342 LM_DBG("Expires header found, value= %d\n", lexpire);
345 LM_DBG("'expires' not found; default=%d\n", event->default_expires);
346 lexpire = event->default_expires;
348 if(lexpire > pres_max_expires) {
349 lexpire = pres_max_expires;
352 /* get pres_uri from Request-URI*/
353 if(parse_sip_msg_uri(msg) < 0) {
354 LM_ERR("parsing Request URI\n");
356 reply_str = pu_400a_rpl;
359 pres_user = msg->parsed_uri.user;
360 pres_domain = msg->parsed_uri.host;
362 if(!msg->content_length) {
363 LM_ERR("no Content-Length header found!\n");
365 reply_str = pu_400a_rpl;
369 /* process the body */
370 if(get_content_length(msg) == 0) {
373 LM_ERR("No E-Tag and no body found\n");
375 reply_str = pu_400b_rpl;
379 body.s = get_body(msg);
381 LM_ERR("cannot extract body\n");
383 reply_str = pu_400a_rpl;
386 body.len = get_content_length(msg);
388 if(pres_sphere_enable && event->evp->type == EVENT_PRESENCE
389 && get_content_type(msg) == SUBTYPE_PIDFXML) {
390 sphere = extract_sphere(&body);
393 memset(&puri, 0, sizeof(struct sip_uri));
395 sender = (str *)pkg_malloc(sizeof(str));
397 ERR_MEM(PKG_MEM_STR);
399 if(sender_uri->len >= buf_len - 1) {
400 LM_ERR("cannot use sender uri -- too long value\n");
403 strncpy(buf, sender_uri->s, sender_uri->len);
404 buf_len = sender_uri->len;
406 if(parse_uri(buf, buf_len, &puri) != 0) {
407 LM_ERR("bad sender SIP address!\n");
409 reply_str = pu_400a_rpl;
412 LM_DBG("using user id [%.*s]\n", buf_len, buf);
415 sender->len = buf_len;
417 /* call event specific handling function*/
418 if(event->evs_publ_handl) {
419 if(event->evs_publ_handl(msg) < 0) {
420 LM_ERR("in event specific publish handling\n");
425 /* now we have all the necessary values */
426 /* fill in the filds of the structure */
428 presentity = new_presentity(
429 &pres_domain, &pres_user, lexpire, event, &etag, sender);
430 if(presentity == NULL) {
431 LM_ERR("creating presentity structure\n");
435 /* querry the database and update or insert */
436 if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply, sphere,
439 LM_ERR("when updating presentity\n");
444 pkg_free(presentity);
456 LM_WARN("Missing or unsupported event header field value\n");
458 if(msg->event && msg->event->body.s && msg->event->body.len > 0)
459 LM_ERR(" event=[%.*s]\n", msg->event->body.len, msg->event->body.s);
461 reply_code = BAD_EVENT_CODE;
462 reply_str = pu_489_rpl;
465 if(sent_reply == 0) {
466 if(send_error_reply(msg, reply_code, reply_str) < 0) {
467 LM_ERR("failed to send error reply\n");
472 pkg_free(presentity);
483 int ki_handle_publish(struct sip_msg *msg)
485 return ki_handle_publish_uri(msg, NULL);
489 * PUBLISH request handling
492 int w_handle_publish(struct sip_msg *msg, char *sender_uri, char *str2)
496 if(sender_uri != NULL
497 && fixup_get_svalue(msg, (gparam_t *)sender_uri, &suri) != 0) {
498 LM_ERR("invalid uri parameter\n");
502 return ki_handle_publish_uri(msg, (sender_uri) ? &suri : NULL);
505 int update_hard_presentity(
506 str *pres_uri, pres_ev_t *event, str *file_uri, str *filename)
508 int ret = -1, new_t, pidf_result;
511 presentity_t *pres = NULL;
512 struct sip_uri parsed_uri;
514 LM_INFO("Hard-state file %.*s (uri %.*s) updated for %.*s\n", filename->len,
515 filename->s, file_uri->len, file_uri->s, pres_uri->len,
518 if(!event->get_pidf_doc) {
519 LM_WARN("pidf-manipulation not supported for %.*s\n", event->name.len,
524 if(parse_uri(pres_uri->s, pres_uri->len, &parsed_uri) < 0) {
525 LM_ERR("bad presentity URI\n");
529 pidf_result = event->get_pidf_doc(
530 &parsed_uri.user, &parsed_uri.host, file_uri, &pidf_doc);
532 if(pidf_result < 0) {
533 LM_ERR("retrieving pidf-manipulation document\n");
535 } else if(pidf_result > 0) {
536 /* Insert/replace presentity... */
537 LM_DBG("INSERT/REPLACE\n");
540 if(pres_sphere_enable) {
541 sphere = extract_sphere(pidf_doc);
544 doc = xmlParseMemory(pidf_doc->s, pidf_doc->len);
546 LM_ERR("bad body format\n");
558 /* Delete presentity... */
563 pres = new_presentity(
564 &parsed_uri.host, &parsed_uri.user, -1, event, filename, NULL);
566 LM_ERR("creating presentity structure\n");
570 if(update_presentity(
571 NULL, pres, pidf_doc, new_t, NULL, sphere, NULL, NULL, 0)
573 LM_ERR("updating presentity\n");
586 pkg_free(pidf_doc->s);