presence: define modes for publ_cache parameter
[sip-router] / src / modules / presence / publish.c
1 /*
2  * Copyright (C) 2006 Voice Sistem S.R.L.
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
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
10  *
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.
15  *
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
19  *
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio presence module :: Support for PUBLISH handling
25  * \ingroup presence
26  */
27
28
29 #include <time.h>
30
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"
43 #include "presence.h"
44 #include "notify.h"
45 #include "utils_func.h"
46 #include "publish.h"
47 #include "presentity.h"
48
49 extern gen_lock_set_t *set;
50
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");
55
56 struct p_modif
57 {
58         presentity_t *p;
59         str uri;
60 };
61
62 void msg_presentity_clean(unsigned int ticks, void *param)
63 {
64         db_key_t db_keys[2], result_cols[4];
65         db_val_t db_vals[2], *values;
66         db_op_t db_ops[2];
67         db1_res_t *result = NULL;
68         db_row_t *rows;
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;
72         presentity_t pres;
73         str uri = {0, 0}, event, *rules_doc = NULL;
74         static str query_str;
75
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");
79                 return;
80         }
81
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);
87         n_db_cols++;
88
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;
94         n_db_cols++;
95
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;
100
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)
104                         < 0) {
105                 LM_ERR("failed to query database for expired messages\n");
106                 goto delete_pres;
107         }
108
109         if(result == NULL) {
110                 LM_ERR("bad result\n");
111                 return;
112         }
113
114         LM_DBG("found n= %d expires messages\n ", result->n);
115
116         do {
117                 rows = RES_ROWS(result);
118
119                 for(i = 0; i < RES_ROW_N(result); i++) {
120                         values = ROW_VALUES(&rows[i]);
121                         memset(&pres, 0, sizeof(presentity_t));
122
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");
134                                 goto error;
135                         }
136
137                         if(uandd_to_uri(pres.user, pres.domain, &uri) < 0) {
138                                 LM_ERR("constructing uri\n");
139                                 goto error;
140                         }
141
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");
146                                 goto error;
147                         }
148
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);
151
152                         if(pres_force_delete == 1) {
153                                 if(delete_presentity(&pres, NULL) < 0) {
154                                         LM_ERR("Deleting presentity\n");
155                                         goto error;
156                                 }
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");
161                                                 goto error;
162                                         }
163                                 }
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");
169                                         }
170                                         goto error;
171                                 }
172
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");
179                                                 }
180                                                 goto error;
181                                         }
182                                 } else {
183                                         if(delete_presentity(&pres, NULL) < 0) {
184                                                 LM_ERR("Deleting presentity\n");
185                                                 goto error;
186                                         }
187                                 }
188                                 if(pa_dbf.end_transaction) {
189                                         if(pa_dbf.end_transaction(pa_db) < 0) {
190                                                 LM_ERR("in end_transaction\n");
191                                                 goto error;
192                                         }
193                                 }
194                         } else {
195                                 if(pres.event->get_rules_doc
196                                                 && pres.event->get_rules_doc(
197                                                                    &pres.user, &pres.domain, &rules_doc)
198                                                                    < 0) {
199                                         LM_ERR("getting rules doc\n");
200                                         goto error;
201                                 }
202                                 if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc) < 0) {
203                                         LM_ERR("sending Notify request\n");
204                                         goto error;
205                                 }
206                                 if(rules_doc) {
207                                         if(rules_doc->s)
208                                                 pkg_free(rules_doc->s);
209                                         pkg_free(rules_doc);
210                                         rules_doc = NULL;
211                                 }
212                         }
213
214                         pkg_free(uri.s);
215                         uri.s = NULL;
216                 }
217         } while(db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
218                         && RES_ROW_N(result) > 0);
219
220         pa_dbf.free_result(pa_db, result);
221         result = NULL;
222
223         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
224                 LM_ERR("in use_table\n");
225                 goto error;
226         }
227
228         if(pres_notifier_processes == 0) {
229         delete_pres:
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");
232         }
233
234         return;
235
236 error:
237         if(result)
238                 pa_dbf.free_result(pa_db, result);
239         if(uri.s)
240                 pkg_free(uri.s);
241         if(rules_doc) {
242                 if(rules_doc->s)
243                         pkg_free(rules_doc->s);
244                 pkg_free(rules_doc);
245         }
246
247         return;
248 }
249
250 /**
251  * PUBLISH request handling
252  *
253  */
254 int ki_handle_publish_uri(struct sip_msg *msg, str *sender_uri)
255 {
256         struct sip_uri puri;
257         str body;
258         int lexpire;
259         presentity_t *presentity = 0;
260         struct hdr_field *hdr;
261         int found = 0, etag_gen = 0;
262         str etag = {0, 0};
263         str *sender = NULL;
264         static char buf[256];
265         int buf_len = 255;
266         pres_ev_t *event = NULL;
267         str pres_user;
268         str pres_domain;
269         int reply_code;
270         str reply_str;
271         int sent_reply = 0;
272         char *sphere = NULL;
273
274         reply_code = 500;
275         reply_str = pu_500_rpl;
276
277         pres_counter++;
278         if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
279                 LM_ERR("parsing headers\n");
280                 reply_code = 400;
281                 reply_str = pu_400a_rpl;
282                 goto error;
283         }
284         memset(&body, 0, sizeof(str));
285
286         /* inspecting the Event header field */
287
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");
291                         reply_code = 400;
292                         reply_str = pu_400a_rpl;
293                         goto error;
294                 }
295         } else
296                 goto unsupported_event;
297
298         /* search event in the list */
299         event = search_event((event_t *)msg->event->parsed);
300         if(event == NULL) {
301                 goto unsupported_event;
302         }
303
304         /* examine the SIP-If-Match header field */
305         hdr = msg->headers;
306         while(hdr != NULL) {
307                 if(cmp_hdrname_strzn(&hdr->name, "SIP-If-Match", 12) == 0) {
308                         found = 1;
309                         break;
310                 }
311                 hdr = hdr->next;
312         }
313         if(found == 0) {
314                 LM_DBG("SIP-If-Match header not found\n");
315                 etag.s = generate_ETag(0);
316                 if(etag.s == NULL) {
317                         LM_ERR("when generating etag\n");
318                         goto error;
319                 }
320                 etag.len = (strlen(etag.s));
321                 etag_gen = 1;
322                 LM_DBG("new etag  = %.*s \n", etag.len, etag.s);
323         } else {
324                 LM_DBG("SIP-If-Match header found\n");
325                 etag.s = (char *)pkg_malloc((hdr->body.len + 1) * sizeof(char));
326                 if(etag.s == NULL) {
327                         ERR_MEM(PKG_MEM_STR);
328                 }
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);
333         }
334
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");
339                         goto error;
340                 }
341                 lexpire = ((exp_body_t *)msg->expires->parsed)->val;
342                 LM_DBG("Expires header found, value= %d\n", lexpire);
343
344         } else {
345                 LM_DBG("'expires' not found; default=%d\n", event->default_expires);
346                 lexpire = event->default_expires;
347         }
348         if(lexpire > pres_max_expires) {
349                 lexpire = pres_max_expires;
350         }
351
352         /* get pres_uri from Request-URI*/
353         if(parse_sip_msg_uri(msg) < 0) {
354                 LM_ERR("parsing Request URI\n");
355                 reply_code = 400;
356                 reply_str = pu_400a_rpl;
357                 goto error;
358         }
359         pres_user = msg->parsed_uri.user;
360         pres_domain = msg->parsed_uri.host;
361
362         if(!msg->content_length) {
363                 LM_ERR("no Content-Length header found!\n");
364                 reply_code = 400;
365                 reply_str = pu_400a_rpl;
366                 goto error;
367         }
368
369         /* process the body */
370         if(get_content_length(msg) == 0) {
371                 body.s = NULL;
372                 if(etag_gen) {
373                         LM_ERR("No E-Tag and no body found\n");
374                         reply_code = 400;
375                         reply_str = pu_400b_rpl;
376                         goto error;
377                 }
378         } else {
379                 body.s = get_body(msg);
380                 if(body.s == NULL) {
381                         LM_ERR("cannot extract body\n");
382                         reply_code = 400;
383                         reply_str = pu_400a_rpl;
384                         goto error;
385                 }
386                 body.len = get_content_length(msg);
387
388                 if(pres_sphere_enable && event->evp->type == EVENT_PRESENCE
389                                 && get_content_type(msg) == SUBTYPE_PIDFXML) {
390                         sphere = extract_sphere(&body);
391                 }
392         }
393         memset(&puri, 0, sizeof(struct sip_uri));
394         if(sender_uri) {
395                 sender = (str *)pkg_malloc(sizeof(str));
396                 if(sender == NULL) {
397                         ERR_MEM(PKG_MEM_STR);
398                 }
399                 if(sender_uri->len >= buf_len - 1) {
400                         LM_ERR("cannot use sender uri -- too long value\n");
401                         goto error;
402                 }
403                 strncpy(buf, sender_uri->s, sender_uri->len);
404                 buf_len = sender_uri->len;
405                 buf[buf_len] = '\0';
406                 if(parse_uri(buf, buf_len, &puri) != 0) {
407                         LM_ERR("bad sender SIP address!\n");
408                         reply_code = 400;
409                         reply_str = pu_400a_rpl;
410                         goto error;
411                 } else {
412                         LM_DBG("using user id [%.*s]\n", buf_len, buf);
413                 }
414                 sender->s = buf;
415                 sender->len = buf_len;
416         }
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");
421                         goto error;
422                 }
423         }
424
425         /* now we have all the necessary values */
426         /* fill in the filds of the structure */
427
428         presentity = new_presentity(
429                         &pres_domain, &pres_user, lexpire, event, &etag, sender);
430         if(presentity == NULL) {
431                 LM_ERR("creating presentity structure\n");
432                 goto error;
433         }
434
435         /* querry the database and update or insert */
436         if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply, sphere,
437                            NULL, NULL, 0)
438                         < 0) {
439                 LM_ERR("when updating presentity\n");
440                 goto error;
441         }
442
443         if(presentity)
444                 pkg_free(presentity);
445         if(etag.s)
446                 pkg_free(etag.s);
447         if(sender)
448                 pkg_free(sender);
449         if(sphere)
450                 pkg_free(sphere);
451
452         return 1;
453
454 unsupported_event:
455
456         LM_WARN("Missing or unsupported event header field value\n");
457
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);
460
461         reply_code = BAD_EVENT_CODE;
462         reply_str = pu_489_rpl;
463
464 error:
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");
468                 }
469         }
470
471         if(presentity)
472                 pkg_free(presentity);
473         if(etag.s)
474                 pkg_free(etag.s);
475         if(sender)
476                 pkg_free(sender);
477         if(sphere)
478                 pkg_free(sphere);
479
480         return -1;
481 }
482
483 int ki_handle_publish(struct sip_msg *msg)
484 {
485         return ki_handle_publish_uri(msg, NULL);
486 }
487
488 /**
489  * PUBLISH request handling
490  *
491  */
492 int w_handle_publish(struct sip_msg *msg, char *sender_uri, char *str2)
493 {
494         str suri;
495
496         if(sender_uri != NULL
497                         && fixup_get_svalue(msg, (gparam_t *)sender_uri, &suri) != 0) {
498                 LM_ERR("invalid uri parameter\n");
499                 return -1;
500         }
501
502         return ki_handle_publish_uri(msg, (sender_uri) ? &suri : NULL);
503 }
504
505 int update_hard_presentity(
506                 str *pres_uri, pres_ev_t *event, str *file_uri, str *filename)
507 {
508         int ret = -1, new_t, pidf_result;
509         str *pidf_doc = 0;
510         char *sphere = NULL;
511         presentity_t *pres = NULL;
512         struct sip_uri parsed_uri;
513
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,
516                         pres_uri->s);
517
518         if(!event->get_pidf_doc) {
519                 LM_WARN("pidf-manipulation not supported for %.*s\n", event->name.len,
520                                 event->name.s);
521                 return -1;
522         }
523
524         if(parse_uri(pres_uri->s, pres_uri->len, &parsed_uri) < 0) {
525                 LM_ERR("bad presentity URI\n");
526                 return -1;
527         }
528
529         pidf_result = event->get_pidf_doc(
530                         &parsed_uri.user, &parsed_uri.host, file_uri, &pidf_doc);
531
532         if(pidf_result < 0) {
533                 LM_ERR("retrieving pidf-manipulation document\n");
534                 return -1;
535         } else if(pidf_result > 0) {
536                 /* Insert/replace presentity... */
537                 LM_DBG("INSERT/REPLACE\n");
538                 xmlDocPtr doc;
539
540                 if(pres_sphere_enable) {
541                         sphere = extract_sphere(pidf_doc);
542                 }
543
544                 doc = xmlParseMemory(pidf_doc->s, pidf_doc->len);
545                 if(doc == NULL) {
546                         LM_ERR("bad body format\n");
547                         xmlFreeDoc(doc);
548                         xmlCleanupParser();
549                         xmlMemoryDump();
550                         goto done;
551                 }
552                 xmlFreeDoc(doc);
553                 xmlCleanupParser();
554                 xmlMemoryDump();
555
556                 new_t = 1;
557         } else {
558                 /* Delete presentity... */
559                 LM_DBG("DELETE\n");
560                 new_t = 0;
561         }
562
563         pres = new_presentity(
564                         &parsed_uri.host, &parsed_uri.user, -1, event, filename, NULL);
565         if(pres == NULL) {
566                 LM_ERR("creating presentity structure\n");
567                 goto done;
568         }
569
570         if(update_presentity(
571                            NULL, pres, pidf_doc, new_t, NULL, sphere, NULL, NULL, 0)
572                         < 0) {
573                 LM_ERR("updating presentity\n");
574                 goto done;
575         }
576
577         ret = 1;
578
579 done:
580         if(pres)
581                 pkg_free(pres);
582         if(sphere)
583                 pkg_free(sphere);
584         if(pidf_doc) {
585                 if(pidf_doc->s)
586                         pkg_free(pidf_doc->s);
587                 pkg_free(pidf_doc);
588         }
589
590         return ret;
591 }