all: updated FSF address in GPL text
[sip-router] / 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  * History:
21  * --------
22  *  2006-08-15  initial version (Anca Vamanu)
23  */
24
25 /*!
26  * \file
27  * \brief Kamailio presence module :: Support for PUBLISH handling
28  * \ingroup presence 
29  */
30
31
32 #include <time.h>
33
34 #include "../../ut.h"
35 #include "../../str.h"
36 #include "../../parser/parse_to.h"
37 #include "../../parser/parse_uri.h" 
38 #include "../../parser/parse_expires.h" 
39 #include "../../parser/parse_event.h" 
40 #include "../../parser/parse_content.h" 
41 #include "../../lock_ops.h"
42 #include "../../hashes.h"
43 #include "../../lib/kcore/cmpapi.h"
44 #include "../../lib/srdb1/db.h"
45 #include "presence.h"
46 #include "notify.h"
47 #include "utils_func.h"
48 #include "publish.h"
49 #include "presentity.h"
50
51 extern gen_lock_set_t* set;
52
53 static str pu_400a_rpl = str_init("Bad request");
54 static str pu_400b_rpl = str_init("Invalid request");
55 static str pu_500_rpl  = str_init("Server Internal Error");
56 static str pu_489_rpl  = str_init("Bad Event");
57
58 struct p_modif
59 {
60         presentity_t* p;
61         str uri;
62 };
63
64 void msg_presentity_clean(unsigned int ticks,void *param)
65 {
66         db_key_t db_keys[2], result_cols[4];
67         db_val_t db_vals[2], *values;
68         db_op_t  db_ops[2] ;
69         db1_res_t *result = NULL;
70         db_row_t *rows;
71         int n_db_cols = 0, n_result_cols = 0;
72         int event_col, etag_col, user_col, domain_col;
73         int i = 0, num_watchers = 0;
74         presentity_t pres;
75         str uri = {0, 0}, event, *rules_doc = NULL;
76
77         LM_DBG("cleaning expired presentity information\n");
78         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
79         {
80                 LM_ERR("in use_table\n");
81                 return ;
82         }
83
84         db_keys[n_db_cols] = &str_expires_col;
85         db_ops[n_db_cols] = OP_LT;
86         db_vals[n_db_cols].type = DB1_INT;
87         db_vals[n_db_cols].nul = 0;
88         db_vals[n_db_cols].val.int_val = (int)time(NULL);
89         n_db_cols++;
90
91         db_keys[n_db_cols] = &str_expires_col;
92         db_ops[n_db_cols] = OP_GT;
93         db_vals[n_db_cols].type = DB1_INT;
94         db_vals[n_db_cols].nul = 0;
95         db_vals[n_db_cols].val.int_val = 0;
96         n_db_cols++;
97
98         result_cols[user_col= n_result_cols++] = &str_username_col;
99         result_cols[domain_col=n_result_cols++] = &str_domain_col;
100         result_cols[etag_col=n_result_cols++] = &str_etag_col;
101         result_cols[event_col=n_result_cols++] = &str_event_col;
102
103         static str query_str = str_init("username");
104         if (db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, db_keys, db_ops,
105                                 db_vals, result_cols, n_db_cols, n_result_cols,
106                                 &query_str, &result) < 0)
107         {
108                 LM_ERR("failed to query database for expired messages\n");
109                 goto delete_pres;
110         }
111
112         if(result == NULL)
113         {
114                 LM_ERR("bad result\n");
115                 return;
116         }
117
118         LM_DBG("found n= %d expires messages\n ",result->n);
119
120         do {
121                 rows = RES_ROWS(result);
122
123                 for(i = 0; i < RES_ROW_N(result); i++)
124                 {
125                         values = ROW_VALUES(&rows[i]);
126                         memset(&pres, 0, sizeof(presentity_t));
127
128                         pres.user.s = (char *) VAL_STRING(&values[user_col]);
129                         pres.user.len = strlen(pres.user.s);
130                         pres.domain.s = (char *) VAL_STRING(&values[domain_col]);
131                         pres.domain.len = strlen(pres.domain.s);
132                         pres.etag.s = (char *) VAL_STRING(&values[etag_col]);
133                         pres.etag.len = strlen(pres.etag.s);
134                         event.s = (char *) VAL_STRING(&values[event_col]);
135                         event.len = strlen(event.s);
136                         pres.event= contains_event(&event, NULL);
137                         if(pres.event== NULL)
138                         {
139                                 LM_ERR("event not found\n");
140                                 goto error;
141                         }
142
143                         if(uandd_to_uri(pres.user, pres.domain, &uri)< 0)
144                         {
145                                 LM_ERR("constructing uri\n");
146                                 goto error;
147                         }
148                 
149                         /* delete from hash table */
150                         if(publ_cache_enabled && delete_phtable(&uri, pres.event->type)< 0)
151                         {
152                                 LM_ERR("deleting from pres hash table\n");
153                                 goto error;
154                         }
155
156                         LM_DBG("found expired publish for [user]=%.*s  [domanin]=%.*s\n",
157                                 pres.user.len,pres.user.s, pres.domain.len, pres.domain.s);
158
159                         if (pres_notifier_processes > 0)
160                         {
161                                 if ((num_watchers = publ_notify_notifier(uri, pres.event)) < 0)
162                                 {
163                                         LM_ERR("Updating watcher records\n");
164                                         goto error;
165                                 }
166
167                                 if (num_watchers > 0)
168                                 {
169                                         if (mark_presentity_for_delete(&pres) < 0)
170                                         {
171                                                 LM_ERR("Marking presentity\n");
172                                                 goto error;
173                                         }
174                                 }
175                                 else
176                                 {
177                                         if (delete_presentity(&pres) < 0)
178                                         {
179                                                 LM_ERR("Deleting presentity\n");
180                                                 goto error;
181                                         }
182                                 }
183                         }
184                         else
185                         {
186                                 if(pres.event->get_rules_doc && 
187                                         pres.event->get_rules_doc(&pres.user,
188                                                                         &pres.domain,
189                                                                         &rules_doc)< 0)
190                                 {
191                                         LM_ERR("getting rules doc\n");
192                                         goto error;
193                                 }
194                                 if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc)< 0)
195                                 {
196                                         LM_ERR("sending Notify request\n");
197                                         goto error;
198                                 }
199                                 if(rules_doc)
200                                 {
201                                         if(rules_doc->s)
202                                                 pkg_free(rules_doc->s);
203                                         pkg_free(rules_doc);
204                                         rules_doc= NULL;
205                                 }
206                         }
207
208                         pkg_free(uri.s);
209                         uri.s = NULL;
210                 }
211         } while (db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
212                         && RES_ROW_N(result) > 0);
213
214         pa_dbf.free_result(pa_db, result);
215         result = NULL;
216
217         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
218         {
219                 LM_ERR("in use_table\n");
220                 goto error;
221         }
222
223         if (pres_notifier_processes == 0)
224         {
225 delete_pres:
226                 if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, n_db_cols) < 0) 
227                         LM_ERR("failed to delete expired records from DB\n");
228         }
229
230         return;
231
232 error:
233         if(result)
234                 pa_dbf.free_result(pa_db, result);
235         if(uri.s) pkg_free(uri.s);
236         if(rules_doc)
237         {
238                 if(rules_doc->s)
239                         pkg_free(rules_doc->s);
240                 pkg_free(rules_doc);
241         }
242
243         return;
244 }
245
246 /**
247  * PUBLISH request handling
248  *
249  */
250 int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2)
251 {
252         struct sip_uri puri;
253         str body;
254         int lexpire;
255         presentity_t* presentity = 0;
256         struct hdr_field* hdr;
257         int found= 0, etag_gen = 0;
258         str etag={0, 0};
259         str* sender= NULL;
260         static char buf[256];
261         int buf_len= 255;
262         pres_ev_t* event= NULL;
263         str pres_user;
264         str pres_domain;
265         int reply_code;
266         str reply_str;
267         int sent_reply= 0;
268         char* sphere= NULL;
269
270         reply_code= 500;
271         reply_str= pu_500_rpl;
272
273         counter++;
274         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
275         {
276                 LM_ERR("parsing headers\n");
277                 reply_code= 400;
278                 reply_str= pu_400a_rpl;
279                 goto error;
280         }
281         memset(&body, 0, sizeof(str));
282         
283         /* inspecting the Event header field */
284         
285         if(msg->event && msg->event->body.len > 0)
286         {
287                 if (!msg->event->parsed && (parse_event(msg->event) < 0))
288                 {
289                         LM_ERR("cannot parse Event header\n");
290                         reply_code= 400;
291                         reply_str= pu_400a_rpl;
292                         goto error;
293                 }
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         {
302                 goto unsupported_event;
303         }
304         
305         /* examine the SIP-If-Match header field */
306         hdr = msg->headers;
307         while (hdr!= NULL)
308         {
309                 if(cmp_hdrname_strzn(&hdr->name, "SIP-If-Match", 12)==0)
310                 {
311                         found = 1;
312                         break;
313                 }
314                 hdr = hdr->next;
315         }
316         if(found==0 )
317         {
318                 LM_DBG("SIP-If-Match header not found\n");
319                 etag.s = generate_ETag(0);
320                 if(etag.s == NULL)
321                 {
322                         LM_ERR("when generating etag\n");
323                         goto error;
324                 }
325                 etag.len=(strlen(etag.s));
326                 etag_gen=1;
327                 LM_DBG("new etag  = %.*s \n", etag.len, etag.s);
328         }
329         else
330         {
331                 LM_DBG("SIP-If-Match header found\n");
332                 etag.s = (char*)pkg_malloc((hdr->body.len+ 1)* sizeof(char));
333                 if(etag.s== NULL)
334                 {
335                         ERR_MEM(PKG_MEM_STR);
336                 }
337                 memcpy(etag.s, hdr->body.s, hdr->body.len );
338                 etag.len = hdr->body.len;        
339                 etag.s[ etag.len] = '\0';
340                 LM_DBG("existing etag  = %.*s \n", etag.len, etag.s);
341         }
342
343         /* examine the expire header field */
344         if(msg->expires && msg->expires->body.len > 0)
345         {
346                 if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
347                 {
348                         LM_ERR("cannot parse Expires header\n");
349                         goto error;
350                 }
351                 lexpire = ((exp_body_t*)msg->expires->parsed)->val;
352                 LM_DBG("Expires header found, value= %d\n", lexpire);
353
354         }
355         else 
356         {
357                 LM_DBG("'expires' not found; default=%d\n",     event->default_expires);
358                 lexpire = event->default_expires;
359         }
360         if(lexpire > max_expires)
361                 lexpire = max_expires;
362
363         /* get pres_uri from Request-URI*/
364         if(parse_sip_msg_uri(msg)< 0)
365         {
366                 LM_ERR("parsing Request URI\n");
367                 reply_code= 400; 
368                 reply_str= pu_400a_rpl;
369                 goto error;
370         }
371         pres_user= msg->parsed_uri.user;
372         pres_domain= msg->parsed_uri.host;
373
374         if (!msg->content_length) 
375         {
376                 LM_ERR("no Content-Length header found!\n");
377                 reply_code= 400; 
378                 reply_str= pu_400a_rpl;
379                 goto error;
380         }       
381
382         /* process the body */
383         if ( get_content_length(msg) == 0 )
384         {
385                 body.s = NULL;
386                 if (etag_gen)
387                 {
388                         LM_ERR("No E-Tag and no body found\n");
389                         reply_code= 400;
390                         reply_str= pu_400b_rpl;
391                         goto error;
392                 }
393         }
394         else
395         {
396                 body.s=get_body(msg);
397                 if (body.s== NULL) 
398                 {
399                         LM_ERR("cannot extract body\n");
400                         reply_code= 400; 
401                         reply_str= pu_400a_rpl;
402                         goto error;
403                 }
404                 body.len= get_content_length( msg );
405
406                 if(sphere_enable && event->evp->type == EVENT_PRESENCE &&
407                                 get_content_type(msg)== SUBTYPE_PIDFXML)
408                 {
409                         sphere= extract_sphere(body);                   
410                 }
411
412         }       
413         memset(&puri, 0, sizeof(struct sip_uri));
414         if(sender_uri)
415         {
416                 sender=(str*)pkg_malloc(sizeof(str));
417                 if(sender== NULL)
418                 {
419                         ERR_MEM(PKG_MEM_STR);
420                 }       
421                 if(pv_printf(msg, (pv_elem_t*)sender_uri, buf, &buf_len)<0)
422                 {
423                         LM_ERR("cannot print the format\n");
424                         goto error;
425                 }
426                 if(parse_uri(buf, buf_len, &puri)!=0)
427                 {
428                         LM_ERR("bad sender SIP address!\n");
429                         reply_code= 400; 
430                         reply_str= pu_400a_rpl;
431                         goto error;
432                 } 
433                 else 
434                 {
435                         LM_DBG("using user id [%.*s]\n",buf_len,buf);
436                 }
437                 sender->s= buf;
438                 sender->len= buf_len;
439         }
440         /* call event specific handling function*/
441         if(event->evs_publ_handl)
442         {
443                 if(event->evs_publ_handl(msg)< 0)
444                 {
445                         LM_ERR("in event specific publish handling\n");
446                         goto error;
447                 }
448         }
449
450         /* now we have all the necessary values */
451         /* fill in the filds of the structure */
452
453         presentity= new_presentity(&pres_domain, &pres_user, lexpire, event,
454                         &etag, sender);
455         if(presentity== NULL)
456         {
457                 LM_ERR("creating presentity structure\n");
458                 goto error;
459         }
460
461         /* querry the database and update or insert */
462         if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply, sphere) <0)
463         {
464                 LM_ERR("when updating presentity\n");
465                 goto error;
466         }
467
468         if(presentity)
469                 pkg_free(presentity);
470         if(etag.s)
471                 pkg_free(etag.s);
472         if(sender)
473                 pkg_free(sender);
474         if(sphere)
475                 pkg_free(sphere);
476
477         return 1;
478
479 unsupported_event:
480         
481         LM_WARN("Missing or unsupported event header field value\n");
482                 
483         if(msg->event && msg->event->body.s && msg->event->body.len>0)
484                 LM_ERR("    event=[%.*s]\n", msg->event->body.len, msg->event->body.s);
485
486         reply_code= BAD_EVENT_CODE;
487         reply_str=      pu_489_rpl; 
488
489 error:
490         if(sent_reply== 0)
491         {
492                 if(send_error_reply(msg, reply_code, reply_str)< 0)
493                 {
494                         LM_ERR("failed to send error reply\n");
495                 }
496         }
497         
498         if(presentity)
499                 pkg_free(presentity);
500         if(etag.s)
501                 pkg_free(etag.s);
502         if(sender)
503                 pkg_free(sender);
504         if(sphere)
505                 pkg_free(sphere);
506
507         return -1;
508
509 }
510
511 int update_hard_presentity(str *pres_uri, pres_ev_t *event, str *file_uri, str *filename)
512 {
513         int ret = -1, new_t, pidf_result;
514         str *pidf_doc;
515         char *sphere = NULL;
516         presentity_t *pres = NULL;
517         struct sip_uri parsed_uri;
518
519         LM_INFO("Hard-state file %.*s (uri %.*s) updated for %.*s\n",
520                 filename->len, filename->s,
521                 file_uri->len, file_uri->s,
522                 pres_uri->len, pres_uri->s);
523
524         if (!event->get_pidf_doc)
525         {
526                 LM_WARN("pidf-manipulation not supported for %.*s\n", event->name.len, event->name.s);
527                 return -1;
528         }
529
530         if (parse_uri(pres_uri->s, pres_uri->len, &parsed_uri) < 0)
531         {
532                 LM_ERR("bad presentity URI\n");
533                 return -1;
534         }
535
536         pidf_result = event->get_pidf_doc(&parsed_uri.user, &parsed_uri.host, file_uri, &pidf_doc);
537
538         if (pidf_result < 0)
539         {
540                 LM_ERR("retrieving pidf-manipulation document\n");
541                 return -1;
542         }
543         else if (pidf_result > 0)
544         {
545                 /* Insert/replace presentity... */
546                 LM_DBG("INSERT/REPLACE\n");
547                 xmlDocPtr doc;
548
549                 if (sphere_enable)
550                         sphere = extract_sphere(*pidf_doc);
551
552                 doc = xmlParseMemory(pidf_doc->s, pidf_doc->len);
553                 if (doc == NULL)
554                 {
555                         LM_ERR("bad body format\n");
556                         xmlFreeDoc(doc);
557                         xmlCleanupParser();
558                         xmlMemoryDump();
559                         goto done;
560                 }
561                 xmlFreeDoc(doc);
562                 xmlCleanupParser();
563                 xmlMemoryDump();
564
565                 new_t = 1;
566         }
567         else
568         {
569                 /* Delete presentity... */
570                 LM_DBG("DELETE\n");
571                 new_t = 0;
572         }
573
574         pres = new_presentity(&parsed_uri.host, &parsed_uri.user, -1, event, filename, NULL);
575         if (pres == NULL)
576         {
577                 LM_ERR("creating presentity structure\n");
578                 goto done;
579         }
580
581         if (update_presentity(NULL, pres, pidf_doc, new_t, NULL, sphere) < 0)
582         {
583                 LM_ERR("updating presentity\n");
584                 goto done;
585         }
586
587         ret = 1;
588
589 done:
590         if (pres) pkg_free(pres);
591         if (sphere) pkg_free(sphere);
592         if(pidf_doc)
593         {
594                 if(pidf_doc->s)
595                         pkg_free(pidf_doc->s);
596                 pkg_free(pidf_doc);
597         }
598
599         return ret;
600 }