Update to the new event parser in the sip-router core.
[sip-router] / modules_k / presence / presentity.c
1 /*
2  * $Id$
3  *
4  * presence module - presence server implementation
5  *
6  * Copyright (C) 2006 Voice Sistem S.R.L.
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * History:
25  * --------
26  *  2006-08-15  initial version (anca)
27  */
28
29 /*! \file
30  * \brief Kamailio presence module :: Presentity handling
31  * \ingroup presence 
32  */
33
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39
40 #include "../../lib/srdb1/db.h"
41 #include "../../lib/kcore/hash_func.h"
42 #include "../../dprint.h"
43 #include "../../mem/shm_mem.h"
44 #include "../../str.h"
45 #include "../alias_db/alias_db.h"
46 #include "../../data_lump_rpl.h"
47 #include "presentity.h"
48 #include "presence.h" 
49 #include "notify.h"
50 #include "publish.h"
51 #include "hash.h"
52 #include "utils_func.h"
53
54
55 xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
56                                                                                                         const char *ns);
57 static str pu_200_rpl  = str_init("OK");
58 static str pu_412_rpl  = str_init("Conditional request failed");
59
60 #define ETAG_LEN  128
61
62 char* generate_ETag(int publ_count)
63 {
64         char* etag= NULL;
65         int size = 0;
66
67         etag = (char*)pkg_malloc(ETAG_LEN*sizeof(char));
68         if(etag ==NULL)
69         {
70                 ERR_MEM(PKG_MEM_STR);
71         }
72         memset(etag, 0, ETAG_LEN*sizeof(char));
73         size = snprintf (etag, ETAG_LEN, "%c.%d.%d.%d.%d",prefix, startup_time, pid, counter, publ_count);
74         if( size <0 )
75         {
76                 LM_ERR("unsuccessfull snprintf\n ");
77                 pkg_free(etag);
78                 return NULL;
79         }
80         if(size >= ETAG_LEN)
81         {
82                 LM_ERR("buffer size overflown\n");
83                 pkg_free(etag);
84                 return NULL;
85         }
86
87         etag[size] = '\0';
88         LM_DBG("etag= %s / %d\n ",etag, size);
89         return etag;
90
91 error:
92         return NULL;
93
94 }
95
96 int publ_send200ok(struct sip_msg *msg, int lexpire, str etag)
97 {
98         char buf[128];
99         int buf_len= 128, size;
100         str hdr_append= {0, 0}, hdr_append2= {0, 0} ;
101
102         LM_DBG("send 200OK reply\n");   
103         LM_DBG("etag= %s - len= %d\n", etag.s, etag.len);
104         
105         hdr_append.s = buf;
106         hdr_append.s[0]='\0';
107         hdr_append.len = snprintf(hdr_append.s, buf_len, "Expires: %d\r\n",
108                         ((lexpire==0)?0:(lexpire-expires_offset)));
109         if(hdr_append.len < 0)
110         {
111                 LM_ERR("unsuccessful snprintf\n");
112                 goto error;
113         }
114         if(hdr_append.len >= buf_len)
115         {
116                 LM_ERR("buffer size overflown\n");
117                 goto error;
118         }
119         hdr_append.s[hdr_append.len]= '\0';
120                 
121         if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 )
122         {
123                 LM_ERR("unable to add lump_rl\n");
124                 goto error;
125         }
126
127         size= sizeof(char)*(20+etag.len) ;
128         hdr_append2.s = (char *)pkg_malloc(size);
129         if(hdr_append2.s == NULL)
130         {
131                 ERR_MEM(PKG_MEM_STR);
132         }
133         hdr_append2.s[0]='\0';
134         hdr_append2.len = snprintf(hdr_append2.s, size, "SIP-ETag: %s\r\n", etag.s);
135         if(hdr_append2.len < 0)
136         {
137                 LM_ERR("unsuccessful snprintf\n ");
138                 goto error;
139         }
140         if(hdr_append2.len >= size)
141         {
142                 LM_ERR("buffer size overflown\n");
143                 goto error;
144         }
145
146         hdr_append2.s[hdr_append2.len]= '\0';
147         if (add_lump_rpl(msg, hdr_append2.s, hdr_append2.len, LUMP_RPL_HDR)==0 )
148         {
149                 LM_ERR("unable to add lump_rl\n");
150                 goto error;
151         }
152
153         if( slb.send_reply( msg, 200, &pu_200_rpl)== -1)
154         {
155                 LM_ERR("sending reply\n");
156                 goto error;
157         }
158
159         pkg_free(hdr_append2.s);
160         return 0;
161
162 error:
163
164         if(hdr_append2.s)
165                 pkg_free(hdr_append2.s);
166
167         return -1;
168 }       
169 presentity_t* new_presentity( str* domain,str* user,int expires, 
170                 pres_ev_t* event, str* etag, str* sender)
171 {
172         presentity_t *presentity= NULL;
173         int size, init_len;
174         
175         /* allocating memory for presentity */
176         size = sizeof(presentity_t)+ domain->len+ user->len+ etag->len +1;
177         if(sender)
178                 size+= sizeof(str)+ sender->len* sizeof(char);
179         
180         init_len= size;
181
182         presentity = (presentity_t*)pkg_malloc(size);
183         if(presentity == NULL)
184         {
185                 ERR_MEM(PKG_MEM_STR);
186         }
187         memset(presentity, 0, size);
188         size= sizeof(presentity_t);
189
190         presentity->domain.s = (char*)presentity+ size;
191         strncpy(presentity->domain.s, domain->s, domain->len);
192         presentity->domain.len = domain->len;
193         size+= domain->len;     
194         
195         presentity->user.s = (char*)presentity+size;
196         strncpy(presentity->user.s, user->s, user->len);
197         presentity->user.len = user->len;
198         size+= user->len;
199
200         presentity->etag.s = (char*)presentity+ size;
201         memcpy(presentity->etag.s, etag->s, etag->len);
202         presentity->etag.s[etag->len]= '\0';
203         presentity->etag.len = etag->len;
204
205         size+= etag->len+1;
206         
207         if(sender)
208         {
209                 presentity->sender= (str*)((char*)presentity+ size);
210                 size+= sizeof(str);
211                 presentity->sender->s= (char*)presentity + size;
212                 memcpy(presentity->sender->s, sender->s, sender->len);
213                 presentity->sender->len= sender->len;
214                 size+= sender->len;
215         }
216
217         if(size> init_len)
218         {
219                 LM_ERR("buffer size overflow init_len= %d, size= %d\n", init_len, size);
220                 goto error;
221         }
222         presentity->event= event;
223         presentity->expires = expires;
224         presentity->received_time= (int)time(NULL);
225         return presentity;
226     
227 error:
228         if(presentity)
229                 pkg_free(presentity);
230         return NULL;
231 }
232
233 xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
234 {
235         xmlNodePtr cur = node->children;
236         while (cur) {
237                 if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0)
238                         return cur;
239                 cur = cur->next;
240         }
241         return NULL;
242 }
243
244 int check_if_dialog(str body, int *is_dialog)
245 {
246         xmlDocPtr doc;
247         xmlNodePtr node;
248
249         doc = xmlParseMemory(body.s, body.len);
250         if(doc== NULL)
251         {
252                 LM_ERR("failed to parse xml document\n");
253                 return -1;
254         }
255
256         node = doc->children;
257         node = xmlNodeGetChildByName(node, "dialog");
258
259         if(node == NULL)
260                 *is_dialog = 0;
261         else
262                 *is_dialog = 1;
263
264         xmlFreeDoc(doc);
265         return 0;
266 }
267
268
269 int update_presentity(struct sip_msg* msg, presentity_t* presentity, str* body,
270                 int new_t, int* sent_reply, char* sphere)
271 {
272         db_key_t query_cols[12], update_keys[8], result_cols[5];
273         db_op_t  query_ops[12];
274         db_val_t query_vals[12], update_vals[8];
275         db1_res_t *result= NULL;
276         int n_query_cols = 0;
277         int n_update_cols = 0;
278         char* dot= NULL;
279         str etag= {0, 0};
280         str cur_etag= {0, 0};
281         str* rules_doc= NULL;
282         str pres_uri= {0, 0};
283         int rez_body_col, rez_sender_col, n_result_cols= 0;
284         db_row_t *row = NULL ;
285         db_val_t *row_vals = NULL;
286         str old_body, sender;
287         int is_dialog= 0, bla_update_publish= 1;
288
289         *sent_reply= 0;
290         if(presentity->event->req_auth)
291         {
292                 /* get rules_document */
293                 if(presentity->event->get_rules_doc(&presentity->user,
294                                         &presentity->domain, &rules_doc))
295                 {
296                         LM_ERR("getting rules doc\n");
297                         goto error;
298                 }
299         }
300         
301         if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri)< 0)
302         {
303                 LM_ERR("constructing uri from user and domain\n");
304                 goto error;
305         }
306
307
308         query_cols[n_query_cols] = &str_domain_col;
309         query_ops[n_query_cols] = OP_EQ;
310         query_vals[n_query_cols].type = DB1_STR;
311         query_vals[n_query_cols].nul = 0;
312         query_vals[n_query_cols].val.str_val = presentity->domain;
313         n_query_cols++;
314         
315         query_cols[n_query_cols] = &str_username_col;
316         query_ops[n_query_cols] = OP_EQ;
317         query_vals[n_query_cols].type = DB1_STR;
318         query_vals[n_query_cols].nul = 0;
319         query_vals[n_query_cols].val.str_val = presentity->user;
320         n_query_cols++;
321
322         query_cols[n_query_cols] = &str_event_col;
323         query_ops[n_query_cols] = OP_EQ;
324         query_vals[n_query_cols].type = DB1_STR;
325         query_vals[n_query_cols].nul = 0;
326         query_vals[n_query_cols].val.str_val = presentity->event->name;
327         n_query_cols++;
328
329         query_cols[n_query_cols] = &str_etag_col;
330         query_ops[n_query_cols] = OP_EQ;
331         query_vals[n_query_cols].type = DB1_STR;
332         query_vals[n_query_cols].nul = 0;
333         query_vals[n_query_cols].val.str_val = presentity->etag;
334         n_query_cols++;
335
336         result_cols[rez_body_col= n_result_cols++] = &str_body_col;
337         result_cols[rez_sender_col= n_result_cols++] = &str_sender_col;
338
339         if(new_t) 
340         {
341                 /* insert new record in hash_table */
342         
343                 if(insert_phtable(&pres_uri, presentity->event->evp->type, sphere)< 0)
344                 {
345                         LM_ERR("inserting record in hash table\n");
346                         goto error;
347                 }
348                 
349                 /* insert new record into database */   
350                 query_cols[n_query_cols] = &str_expires_col;
351                 query_vals[n_query_cols].type = DB1_INT;
352                 query_vals[n_query_cols].nul = 0;
353                 query_vals[n_query_cols].val.int_val = presentity->expires+
354                                 (int)time(NULL);
355                 n_query_cols++;
356         
357                 if( presentity->sender)
358                 {
359                         query_cols[n_query_cols] = &str_sender_col;
360                         query_vals[n_query_cols].type = DB1_STR;
361                         query_vals[n_query_cols].nul = 0;
362                         query_vals[n_query_cols].val.str_val.s = presentity->sender->s;
363                         query_vals[n_query_cols].val.str_val.len = presentity->sender->len;
364                         n_query_cols++;
365                 }
366
367                 query_cols[n_query_cols] = &str_body_col;
368                 query_vals[n_query_cols].type = DB1_BLOB;
369                 query_vals[n_query_cols].nul = 0;
370                 query_vals[n_query_cols].val.str_val = *body;
371                 n_query_cols++;
372                 
373                 query_cols[n_query_cols] = &str_received_time_col;
374                 query_vals[n_query_cols].type = DB1_INT;
375                 query_vals[n_query_cols].nul = 0;
376                 query_vals[n_query_cols].val.int_val = presentity->received_time;
377                 n_query_cols++;
378                 
379                 if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
380                 {
381                         LM_ERR("unsuccessful use_table\n");
382                         goto error;
383                 }
384
385                 LM_DBG("inserting %d cols into table\n",n_query_cols);
386                                 
387                 if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) 
388                 {
389                         LM_ERR("inserting new record in database\n");
390                         goto error;
391                 }
392                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
393                 {
394                         LM_ERR("sending 200OK\n");
395                         goto error;
396                 }
397                 *sent_reply= 1;
398                 goto send_notify;
399         }
400         else
401         {       
402                 if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
403                 {
404                         LM_ERR("unsuccessful sql use table\n");
405                         goto error;
406                 }
407
408                 if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
409                          result_cols, n_query_cols, n_result_cols, 0, &result) < 0) 
410                 {
411                         LM_ERR("unsuccessful sql query\n");
412                         goto error;
413                 }
414                 if(result== NULL)
415                         goto error;
416
417                 if (result->n > 0)
418                 {
419
420                         if(EVENT_DIALOG_SLA(presentity->event->evp))
421                         {
422                                 /* analize if previous body has a dialog */
423                                 row = &result->rows[0];
424                                 row_vals = ROW_VALUES(row);
425
426                                 old_body.s = (char*)row_vals[rez_body_col].val.string_val;
427                                 old_body.len = strlen(old_body.s);
428                                 if(check_if_dialog(*body, &is_dialog)< 0)
429                                 {
430                                         LM_ERR("failed to check if dialog stored\n");
431                                         goto error;
432                                 }
433
434                                 if(is_dialog== 1)  /* if the new body has a dialog - overwrite */
435                                         goto after_dialog_check;
436
437                                 if(check_if_dialog(old_body, &is_dialog)< 0)
438                                 {
439                                         LM_ERR("failed to check if dialog stored\n");
440                                         goto error;
441                                 }
442
443                                 if(is_dialog==0 ) /* if the old body has no dialog - overwrite */
444                                         goto after_dialog_check;
445
446                                 sender.s = (char*)row_vals[rez_sender_col].val.string_val;
447                                 sender.len= strlen(sender.s);
448
449                                 LM_DBG("old_sender = %.*s\n", sender.len, sender.s );
450                                 if(presentity->sender)
451                                 {
452                                         if(!(presentity->sender->len == sender.len && 
453                                         strncmp(presentity->sender->s, sender.s, sender.len)== 0))
454                                                  bla_update_publish= 0;
455                                 }
456                         }
457 after_dialog_check:
458
459                         pa_dbf.free_result(pa_db, result);
460                         result= NULL;
461                         if(presentity->expires == 0) 
462                         {
463                                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
464                                 {
465                                         LM_ERR("sending 200OK reply\n");
466                                         goto error;
467                                 }
468                                 *sent_reply= 1;
469                                 if( publ_notify( presentity, pres_uri, body, &presentity->etag, rules_doc)< 0 )
470                                 {
471                                         LM_ERR("while sending notify\n");
472                                         goto error;
473                                 }
474                                 
475                                 if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
476                                 {
477                                         LM_ERR("unsuccessful sql use table\n");
478                                         goto error;
479                                 }
480
481                                 LM_DBG("expires =0 -> deleting from database\n");
482                                 if(pa_dbf.delete(pa_db,query_cols,0,query_vals,n_query_cols)<0)
483                                 {
484                                         LM_ERR("unsuccessful sql delete operation");
485                                         goto error;
486                                 }
487                                 LM_DBG("deleted from db %.*s\n",        presentity->user.len,
488                                                 presentity->user.s);
489
490                                 /* delete from hash table */
491         
492                                 if(delete_phtable(&pres_uri, presentity->event->evp->type)< 0)
493                                 {
494                                         LM_ERR("deleting record from hash table\n");
495                                         goto error;
496                                 }
497                                 goto done;
498                         }
499
500                         n_update_cols= 0;
501                         /* if event dialog and is_dialog -> if sender not the same as
502                          * old sender do not overwrite */
503                         if( EVENT_DIALOG_SLA(presentity->event->evp) &&  bla_update_publish==0)
504                         {
505                                 LM_DBG("drop Publish for BLA from a different sender that"
506                                                 " wants to overwrite an existing dialog\n");
507                                 LM_DBG("sender = %.*s\n",  presentity->sender->len, presentity->sender->s );
508                                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
509                                 {
510                                         LM_ERR("sending 200OK reply\n");
511                                         goto error;
512                                 }
513                                 *sent_reply= 1;
514                                 goto done;
515                         }
516
517                         if(presentity->event->etag_not_new== 0)
518                         {       
519                                 /* generate another etag */
520                                 unsigned int publ_nr;
521                                 str str_publ_nr= {0, 0};
522
523                                 dot= presentity->etag.s+ presentity->etag.len;
524                                 while(*dot!= '.' && str_publ_nr.len< presentity->etag.len)
525                                 {
526                                         str_publ_nr.len++;
527                                         dot--;
528                                 }
529                                 if(str_publ_nr.len== presentity->etag.len)
530                                 {
531                                         LM_ERR("wrong etag\n");
532                                         goto error;
533                                 }       
534                                 str_publ_nr.s= dot+1;
535                                 str_publ_nr.len--;
536         
537                                 if( str2int(&str_publ_nr, &publ_nr)< 0)
538                                 {
539                                         LM_ERR("converting string to int\n");
540                                         goto error;
541                                 }
542                                 etag.s = generate_ETag(publ_nr+1);
543                                 if(etag.s == NULL)
544                                 {
545                                         LM_ERR("while generating etag\n");
546                                         goto error;
547                                 }
548                                 etag.len=(strlen(etag.s));
549                                 
550                                 cur_etag= etag;
551
552                                 update_keys[n_update_cols] = &str_etag_col;
553                                 update_vals[n_update_cols].type = DB1_STR;
554                                 update_vals[n_update_cols].nul = 0;
555                                 update_vals[n_update_cols].val.str_val = etag;
556                                 n_update_cols++;
557
558                         }
559                         else
560                                 cur_etag= presentity->etag;
561                         
562                         update_keys[n_update_cols] = &str_expires_col;
563                         update_vals[n_update_cols].type = DB1_INT;
564                         update_vals[n_update_cols].nul = 0;
565                         update_vals[n_update_cols].val.int_val= presentity->expires +
566                                 (int)time(NULL);
567                         n_update_cols++;
568
569                         update_keys[n_update_cols] = &str_received_time_col;
570                         update_vals[n_update_cols].type = DB1_INT;
571                         update_vals[n_update_cols].nul = 0;
572                         update_vals[n_update_cols].val.int_val= presentity->received_time;
573                         n_update_cols++;
574
575                         if(body && body->s)
576                         {
577                                 update_keys[n_update_cols] = &str_body_col;
578                                 update_vals[n_update_cols].type = DB1_BLOB;
579                                 update_vals[n_update_cols].nul = 0;
580                                 update_vals[n_update_cols].val.str_val = *body;
581                                 n_update_cols++;
582
583                                 /* updated stored sphere */
584                                 if(sphere_enable && 
585                                                 presentity->event->evp->type== EVENT_PRESENCE)
586                                 {
587                                         if(update_phtable(presentity, pres_uri, *body)< 0)
588                                         {
589                                                 LM_ERR("failed to update sphere for presentity\n");
590                                                 goto error;
591                                         }
592                                 }
593                         }
594                         
595                         if( presentity->sender)
596                         {
597                                 update_keys[n_update_cols] = &str_sender_col;
598                                 update_vals[n_update_cols].type = DB1_STR;
599                                 update_vals[n_update_cols].nul = 0;
600                                 update_vals[n_update_cols].val.str_val = *presentity->sender;
601                                 n_update_cols++;
602                         }
603
604                         if( pa_dbf.update( pa_db,query_cols, query_ops, query_vals,
605                                         update_keys, update_vals, n_query_cols, n_update_cols )<0) 
606                         {
607                                 LM_ERR("updating published info in database\n");
608                                 goto error;
609                         }
610                         
611                         /* send 200OK */
612                         if( publ_send200ok(msg, presentity->expires, cur_etag)< 0)
613                         {
614                                 LM_ERR("sending 200OK reply\n");
615                                 goto error;
616                         }
617                         *sent_reply= 1;
618                         
619                         if(etag.s)
620                                 pkg_free(etag.s);
621                         etag.s= NULL;
622                         
623                         if(!body)
624                                 goto done;
625                 
626                         goto send_notify;
627                 }  
628                 else  /* if there isn't no registration with those 3 values */
629                 {
630                         pa_dbf.free_result(pa_db, result);
631                         result= NULL;
632                         LM_ERR("No E_Tag match\n");
633                         if (slb.send_reply(msg, 412, &pu_412_rpl) == -1)
634                         {
635                                 LM_ERR("sending '412 Conditional request failed' reply\n");
636                                 goto error;
637                         }
638                         *sent_reply= 1;
639                         goto done;
640                 }
641         }
642
643 send_notify:
644                         
645         /* send notify with presence information */
646         if (publ_notify(presentity, pres_uri, body, NULL, rules_doc)<0)
647         {
648                 LM_ERR("while sending Notify requests to watchers\n");
649                 goto error;
650         }
651
652 done:
653         if(rules_doc)
654         {
655                 if(rules_doc->s)
656                         pkg_free(rules_doc->s);
657                 pkg_free(rules_doc);
658         }
659         if(pres_uri.s)
660                 pkg_free(pres_uri.s);
661
662         return 0;
663
664 error:
665         if(result)
666                 pa_dbf.free_result(pa_db, result);
667         if(etag.s)
668                 pkg_free(etag.s);
669         if(rules_doc)
670         {
671                 if(rules_doc->s)
672                         pkg_free(rules_doc->s);
673                 pkg_free(rules_doc);
674         }
675         if(pres_uri.s)
676                 pkg_free(pres_uri.s);
677
678         return -1;
679
680 }
681
682 int pres_htable_restore(void)
683 {
684         /* query all records from presentity table and insert records 
685          * in presentity table */
686         db_key_t result_cols[6];
687         db1_res_t *result= NULL;
688         db_row_t *row= NULL ;   
689         db_val_t *row_vals;
690         int  i;
691         str user, domain, ev_str, uri, body;
692         int n_result_cols= 0;
693         int user_col, domain_col, event_col, expires_col, body_col = 0;
694         int event;
695         event_t ev;
696         char* sphere= NULL;
697
698         result_cols[user_col= n_result_cols++]= &str_username_col;
699         result_cols[domain_col= n_result_cols++]= &str_domain_col;
700         result_cols[event_col= n_result_cols++]= &str_event_col;
701         result_cols[expires_col= n_result_cols++]= &str_expires_col;
702         if(sphere_enable)
703                 result_cols[body_col= n_result_cols++]= &str_body_col;
704
705         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
706         {
707                 LM_ERR("unsuccessful use table sql operation\n");
708                 goto error;
709         }
710         static str query_str = str_init("username");
711         if (pa_dbf.query (pa_db, 0, 0, 0,result_cols,0, n_result_cols,
712                                 &query_str, &result) < 0)
713         {
714                 LM_ERR("querying presentity\n");
715                 goto error;
716         }
717         if(result== NULL)
718                 goto error;
719
720         if(result->n<= 0)
721         {
722                 pa_dbf.free_result(pa_db, result);
723                 return 0;
724         }
725                 
726         for(i= 0; i< result->n; i++)
727         {
728                 row = &result->rows[i];
729                 row_vals = ROW_VALUES(row);
730
731                 if(row_vals[expires_col].val.int_val< (int)time(NULL))
732                         continue;
733                 
734                 sphere= NULL;
735                 user.s= (char*)row_vals[user_col].val.string_val;
736                 user.len= strlen(user.s);
737                 domain.s= (char*)row_vals[domain_col].val.string_val;
738                 domain.len= strlen(domain.s);
739                 ev_str.s= (char*)row_vals[event_col].val.string_val;
740                 ev_str.len= strlen(ev_str.s);
741
742                 if(event_parser(ev_str.s, ev_str.len, &ev)< 0)
743                 {
744                         LM_ERR("parsing event\n");
745                         free_event_params(ev.params.list, PKG_MEM_TYPE);
746                         goto error;
747                 }
748                 event= ev.type;
749                 free_event_params(ev.params.list, PKG_MEM_TYPE);
750
751                 if(uandd_to_uri(user, domain, &uri)< 0)
752                 {
753                         LM_ERR("constructing uri\n");
754                         goto error;
755                 }
756                 /* insert in hash_table*/
757         
758                 if(sphere_enable && event== EVENT_PRESENCE )
759                 {
760                         body.s= (char*)row_vals[body_col].val.string_val;
761                         body.len= strlen(body.s);
762                         sphere= extract_sphere(body);
763                 }
764
765                 if(insert_phtable(&uri, event, sphere)< 0)
766                 {
767                         LM_ERR("inserting record in presentity hash table");
768                         pkg_free(uri.s);
769                         if(sphere)
770                                 pkg_free(sphere);
771                         goto error;
772                 }
773                 if(sphere)
774                         pkg_free(sphere);
775                 pkg_free(uri.s);
776         }
777         pa_dbf.free_result(pa_db, result);
778
779         return 0;
780
781 error:
782         if(result)
783                 pa_dbf.free_result(pa_db, result);
784         return -1;      
785 }
786
787 char* extract_sphere(str body)
788 {
789
790         /* check for a rpid sphere element */
791         xmlDocPtr doc= NULL;
792         xmlNodePtr node;
793         char* cont, *sphere= NULL;
794         
795
796         doc= xmlParseMemory(body.s, body.len);
797         if(doc== NULL)
798         {
799                 LM_ERR("failed to parse xml body\n");
800                 return NULL;
801         }
802
803         node= xmlNodeGetNodeByName(doc->children, "sphere", "rpid");
804         
805         if(node== NULL)
806                 node= xmlNodeGetNodeByName(doc->children, "sphere", "r");
807
808         if(node)
809         {
810                 LM_DBG("found sphere definition\n");
811                 cont= (char*)xmlNodeGetContent(node);
812                 if(cont== NULL)
813                 {
814                         LM_ERR("failed to extract sphere node content\n");
815                         goto error;
816                 }
817                 sphere= (char*)pkg_malloc((strlen(cont)+ 1)*sizeof(char));
818                 if(sphere== NULL)
819                 {
820                         xmlFree(cont);
821                         ERR_MEM(PKG_MEM_STR);
822                 }
823                 strcpy(sphere, cont);
824                 xmlFree(cont);
825         }
826         else
827                 LM_DBG("didn't find sphere definition\n");
828
829 error:
830         xmlFreeDoc(doc);
831
832         return sphere;
833 }
834
835 xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
836                                                                                                         const char *ns)
837 {
838         xmlNodePtr cur = node;
839         while (cur) {
840                 xmlNodePtr match = NULL;
841                 if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0) {
842                         if (!ns || (cur->ns && xmlStrcasecmp(cur->ns->prefix,
843                                                         (unsigned char*)ns) == 0))
844                                 return cur;
845                 }
846                 match = xmlNodeGetNodeByName(cur->children, name, ns);
847                 if (match)
848                         return match;
849                 cur = cur->next;
850         }
851         return NULL;
852 }
853
854 char* get_sphere(str* pres_uri)
855 {
856         unsigned int hash_code;
857         char* sphere= NULL;
858         pres_entry_t* p;
859         db_key_t query_cols[6];
860         db_val_t query_vals[6];
861         db_key_t result_cols[6];
862         db1_res_t *result = NULL;
863         db_row_t *row= NULL ;   
864         db_val_t *row_vals;
865         int n_result_cols = 0;
866         int n_query_cols = 0;
867         struct sip_uri uri;
868         str body;
869
870
871         if(!sphere_enable)
872                 return NULL;
873
874         /* search in hash table*/
875         hash_code= core_hash(pres_uri, NULL, phtable_size);
876
877         lock_get(&pres_htable[hash_code].lock);
878
879         p= search_phtable(pres_uri, EVENT_PRESENCE, hash_code);
880
881         if(p)
882         {
883                 if(p->sphere)
884                 {
885                         sphere= (char*)pkg_malloc(strlen(p->sphere)* sizeof(char));
886                         if(sphere== NULL)
887                         {
888                                 lock_release(&pres_htable[hash_code].lock);
889                                 ERR_MEM(PKG_MEM_STR);
890                         }
891                         strcpy(sphere, p->sphere);
892                 }
893                 lock_release(&pres_htable[hash_code].lock);
894                 return sphere;
895         }
896         lock_release(&pres_htable[hash_code].lock);
897
898
899         /* if record not found and fallback2db query database*/
900         if(!fallback2db)
901         {
902                 return NULL;
903         }
904
905         if(parse_uri(pres_uri->s, pres_uri->len, &uri)< 0)
906         {
907                 LM_ERR("failed to parse presentity uri\n");
908                 goto error;
909         }
910
911         query_cols[n_query_cols] = &str_domain_col;
912         query_vals[n_query_cols].type = DB1_STR;
913         query_vals[n_query_cols].nul = 0;
914         query_vals[n_query_cols].val.str_val = uri.host;
915         n_query_cols++;
916
917         query_cols[n_query_cols] = &str_username_col;
918         query_vals[n_query_cols].type = DB1_STR;
919         query_vals[n_query_cols].nul = 0;
920         query_vals[n_query_cols].val.str_val = uri.user;
921         n_query_cols++;
922
923         query_cols[n_query_cols] = &str_event_col;
924         query_vals[n_query_cols].type = DB1_STR;
925         query_vals[n_query_cols].nul = 0;
926         query_vals[n_query_cols].val.str_val.s= "presence";
927         query_vals[n_query_cols].val.str_val.len= 8;
928         n_query_cols++;
929
930         result_cols[n_result_cols++] = &str_body_col;
931         
932         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
933         {
934                 LM_ERR("in use_table\n");
935                 return NULL;
936         }
937
938         static str query_str = str_init("received_time");
939         if (pa_dbf.query (pa_db, query_cols, 0, query_vals,
940                  result_cols, n_query_cols, n_result_cols, &query_str ,  &result) < 0) 
941         {
942                 LM_ERR("failed to query %.*s table\n", presentity_table.len, presentity_table.s);
943                 if(result)
944                         pa_dbf.free_result(pa_db, result);
945                 return NULL;
946         }
947         
948         if(result== NULL)
949                 return NULL;
950
951         if (result->n<=0 )
952         {
953                 LM_DBG("no published record found in database\n");
954                 pa_dbf.free_result(pa_db, result);
955                 return NULL;
956         }
957
958         row = &result->rows[result->n-1];
959         row_vals = ROW_VALUES(row);
960         if(row_vals[0].val.string_val== NULL)
961         {
962                 LM_ERR("NULL notify body record\n");
963                 goto error;
964         }
965
966         body.s= (char*)row_vals[0].val.string_val;
967         body.len= strlen(body.s);
968         if(body.len== 0)
969         {
970                 LM_ERR("Empty notify body record\n");
971                 goto error;
972         }
973         
974         sphere= extract_sphere(body);
975
976         pa_dbf.free_result(pa_db, result);
977
978         return sphere;
979
980 error:
981         if(result)
982                 pa_dbf.free_result(pa_db, result);
983         return NULL;
984
985 }
986