c17dbbe88bdd79be90cc1e09d89ea25977153ae1
[sip-router] / src / modules / presence / presentity.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 :: Presentity handling
25  * \ingroup presence
26  */
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33
34 #include "../../lib/srdb1/db.h"
35 #include "../../core/hashes.h"
36 #include "../../core/dprint.h"
37 #include "../../core/mem/shm_mem.h"
38 #include "../../core/xavp.h"
39 #include "../../core/str.h"
40 #include "../../core/data_lump_rpl.h"
41 #include "presentity.h"
42 #include "presence.h"
43 #include "notify.h"
44 #include "publish.h"
45 #include "hash.h"
46 #include "utils_func.h"
47 #include "presence_dmq.h"
48
49
50 /* base priority value (20150101T000000) */
51 #define PRES_PRIORITY_TBASE 1420070400
52
53 xmlNodePtr xmlNodeGetNodeByName(
54                 xmlNodePtr node, const char *name, const char *ns);
55 static str pu_200_rpl = str_init("OK");
56 static str pu_412_rpl = str_init("Conditional request failed");
57
58 static str str_offline_etag_val = str_init("*#-OFFLINE-#*");
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                 ERR_MEM(PKG_MEM_STR);
70         }
71         memset(etag, 0, ETAG_LEN * sizeof(char));
72         size = snprintf(etag, ETAG_LEN, "%c.%d.%d.%d.%d", pres_prefix,
73                         pres_startup_time, pres_pid, pres_counter, publ_count);
74         if(size < 0) {
75                 LM_ERR("unsuccessful snprintf\n ");
76                 pkg_free(etag);
77                 return NULL;
78         }
79         if(size >= ETAG_LEN) {
80                 LM_ERR("buffer size overflown\n");
81                 pkg_free(etag);
82                 return NULL;
83         }
84
85         etag[size] = '\0';
86         LM_DBG("etag= %s / %d\n ", etag, size);
87         return etag;
88
89 error:
90         return NULL;
91 }
92
93 int publ_send200ok(struct sip_msg *msg, int lexpire, str etag)
94 {
95         char buf[128];
96         int buf_len = 128, size;
97         str hdr_append = {0, 0}, hdr_append2 = {0, 0};
98
99         if(msg == NULL)
100                 return 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 - pres_expires_offset)));
109         if(hdr_append.len < 0) {
110                 LM_ERR("unsuccessful snprintf\n");
111                 goto error;
112         }
113         if(hdr_append.len >= buf_len) {
114                 LM_ERR("buffer size overflown\n");
115                 goto error;
116         }
117         hdr_append.s[hdr_append.len] = '\0';
118
119         if(add_lump_rpl(msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR) == 0) {
120                 LM_ERR("unable to add lump_rl\n");
121                 goto error;
122         }
123
124         size = sizeof(char) * (20 + etag.len);
125         hdr_append2.s = (char *)pkg_malloc(size);
126         if(hdr_append2.s == NULL) {
127                 ERR_MEM(PKG_MEM_STR);
128         }
129         hdr_append2.s[0] = '\0';
130         hdr_append2.len = snprintf(hdr_append2.s, size, "SIP-ETag: %s\r\n", etag.s);
131         if(hdr_append2.len < 0) {
132                 LM_ERR("unsuccessful snprintf\n ");
133                 goto error;
134         }
135         if(hdr_append2.len >= size) {
136                 LM_ERR("buffer size overflown\n");
137                 goto error;
138         }
139
140         hdr_append2.s[hdr_append2.len] = '\0';
141         if(add_lump_rpl(msg, hdr_append2.s, hdr_append2.len, LUMP_RPL_HDR) == 0) {
142                 LM_ERR("unable to add lump_rl\n");
143                 goto error;
144         }
145
146         if(slb.freply(msg, 200, &pu_200_rpl) < 0) {
147                 LM_ERR("sending reply\n");
148                 goto error;
149         }
150
151         pkg_free(hdr_append2.s);
152         return 0;
153
154 error:
155
156         if(hdr_append2.s)
157                 pkg_free(hdr_append2.s);
158
159         return -1;
160 }
161
162 /**
163  * get priority value for presence document
164  */
165 unsigned int pres_get_priority(void)
166 {
167         sr_xavp_t *vavp = NULL;
168         str vname = str_init("priority");
169
170         if(pres_xavp_cfg.s == NULL || pres_xavp_cfg.len <= 0) {
171                 return 0;
172         }
173
174         vavp = xavp_get_child_with_ival(&pres_xavp_cfg, &vname);
175         if(vavp != NULL) {
176                 return (unsigned int)vavp->val.v.i;
177         }
178
179         return (unsigned int)(time(NULL) - PRES_PRIORITY_TBASE);
180 }
181
182 /**
183  * create new presentity record
184  */
185 presentity_t *new_presentity(str *domain, str *user, int expires,
186                 pres_ev_t *event, str *etag, str *sender)
187 {
188         presentity_t *presentity = NULL;
189         int size, init_len;
190
191         /* allocating memory for presentity */
192         size = sizeof(presentity_t) + domain->len + user->len + etag->len + 1;
193         if(sender)
194                 size += sizeof(str) + sender->len * sizeof(char);
195
196         init_len = size;
197
198         presentity = (presentity_t *)pkg_malloc(size);
199         if(presentity == NULL) {
200                 ERR_MEM(PKG_MEM_STR);
201         }
202         memset(presentity, 0, size);
203         size = sizeof(presentity_t);
204
205         presentity->domain.s = (char *)presentity + size;
206         strncpy(presentity->domain.s, domain->s, domain->len);
207         presentity->domain.len = domain->len;
208         size += domain->len;
209
210         presentity->user.s = (char *)presentity + size;
211         strncpy(presentity->user.s, user->s, user->len);
212         presentity->user.len = user->len;
213         size += user->len;
214
215         presentity->etag.s = (char *)presentity + size;
216         memcpy(presentity->etag.s, etag->s, etag->len);
217         presentity->etag.s[etag->len] = '\0';
218         presentity->etag.len = etag->len;
219
220         size += etag->len + 1;
221
222         if(sender) {
223                 presentity->sender = (str *)((char *)presentity + size);
224                 size += sizeof(str);
225                 presentity->sender->s = (char *)presentity + size;
226                 memcpy(presentity->sender->s, sender->s, sender->len);
227                 presentity->sender->len = sender->len;
228                 size += sender->len;
229         }
230
231         if(size > init_len) {
232                 LM_ERR("buffer size overflow init_len= %d, size= %d\n", init_len, size);
233                 goto error;
234         }
235         presentity->event = event;
236         presentity->expires = expires;
237         presentity->received_time = (int)time(NULL);
238         presentity->priority = pres_get_priority();
239         return presentity;
240
241 error:
242         if(presentity)
243                 pkg_free(presentity);
244         return NULL;
245 }
246
247 xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
248 {
249         xmlNodePtr cur = node->children;
250         while(cur) {
251                 if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0)
252                         return cur;
253                 cur = cur->next;
254         }
255         return NULL;
256 }
257
258 int check_if_dialog(str body, int *is_dialog, char **dialog_id)
259 {
260         xmlDocPtr doc;
261         xmlNodePtr node;
262         char *tmp_dialog_id;
263
264         *dialog_id = NULL;
265         *is_dialog = 0;
266
267         doc = xmlParseMemory(body.s, body.len);
268         if(doc == NULL) {
269                 LM_INFO("failed to parse xml document\n");
270                 return -1;
271         }
272
273         node = doc->children;
274         node = xmlNodeGetChildByName(node, "dialog");
275
276         if(node != NULL) {
277                 *is_dialog = 1;
278                 tmp_dialog_id = (char *)xmlGetProp(node, (xmlChar *)"id");
279
280                 if(tmp_dialog_id != NULL) {
281                         *dialog_id = strdup(tmp_dialog_id);
282                         xmlFree(tmp_dialog_id);
283                 }
284         }
285
286         xmlFreeDoc(doc);
287         return 0;
288 }
289
290 /**
291  * return 1 if all dialog nodes have the vstate
292  *   * 0 if at least one state is different
293  *   * -1 in case of error
294  */
295 int ps_match_dialog_state_from_body(str body, int *is_dialog, char *vstate)
296 {
297         xmlDocPtr doc;
298         xmlNodePtr node;
299         xmlNodePtr fnode;
300         xmlNodePtr childNode;
301         char *tmp_state;
302         int rmatch = 0;
303
304         *is_dialog = 0;
305
306         doc = xmlParseMemory(body.s, body.len);
307         if(doc == NULL || doc->children == NULL) {
308                 LM_ERR("failed to parse xml document\n");
309                 return -1;
310         }
311
312         fnode = node = xmlNodeGetChildByName(doc->children, "dialog");
313
314         while(node != NULL) {
315                 *is_dialog = 1;
316
317                 childNode = xmlNodeGetChildByName(node, "state");
318                 tmp_state = (char *)xmlNodeGetContent(childNode);
319
320                 if(tmp_state != NULL) {
321                         if(strcmp(tmp_state, vstate) != 0) {
322                                 /* state not matched */
323                                 xmlFree(tmp_state);
324                                 rmatch = 0;
325                                 goto done;
326                         }
327                         rmatch = 1;
328                         xmlFree(tmp_state);
329                 }
330                 /* search for next dialog node */
331                 do {
332                         if(node->next != NULL && node->next->name != NULL
333                                         && xmlStrcmp(fnode->name, node->next->name) == 0) {
334                                 node = node->next;
335                                 break;
336                         }
337                         node = node->next;
338                 } while(node != NULL);
339         }
340
341 done:
342         xmlFreeDoc(doc);
343         return rmatch;
344 }
345
346 int delete_presentity_if_dialog_id_exists(
347                 presentity_t *presentity, char *dialog_id)
348 {
349         db_key_t query_cols[13], result_cols[6];
350         db_op_t query_ops[13];
351         db_val_t query_vals[13];
352         int n_query_cols = 0;
353         int rez_body_col = 0, rez_etag_col = 0, n_result_cols = 0;
354         db1_res_t *result = NULL;
355         db_row_t *row = NULL;
356         db_val_t *row_vals = NULL;
357         char *db_dialog_id = NULL;
358         int db_is_dialog = 0;
359         str tmp_db_body, tmp_db_etag;
360         int i = 0;
361         presentity_t old_presentity;
362
363         if(presentity->event->evp->type != EVENT_DIALOG) {
364                 return 0;
365         }
366
367         query_cols[n_query_cols] = &str_domain_col;
368         query_ops[n_query_cols] = OP_EQ;
369         query_vals[n_query_cols].type = DB1_STR;
370         query_vals[n_query_cols].nul = 0;
371         query_vals[n_query_cols].val.str_val = presentity->domain;
372         n_query_cols++;
373
374         query_cols[n_query_cols] = &str_username_col;
375         query_ops[n_query_cols] = OP_EQ;
376         query_vals[n_query_cols].type = DB1_STR;
377         query_vals[n_query_cols].nul = 0;
378         query_vals[n_query_cols].val.str_val = presentity->user;
379         n_query_cols++;
380
381         query_cols[n_query_cols] = &str_event_col;
382         query_ops[n_query_cols] = OP_EQ;
383         query_vals[n_query_cols].type = DB1_STR;
384         query_vals[n_query_cols].nul = 0;
385         query_vals[n_query_cols].val.str_val = presentity->event->name;
386         n_query_cols++;
387
388         result_cols[rez_body_col = n_result_cols++] = &str_body_col;
389         result_cols[rez_etag_col = n_result_cols++] = &str_etag_col;
390
391         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
392                 LM_ERR("unsuccessful sql use table\n");
393                 return -1;
394         }
395
396         if(pa_dbf.query(pa_db, query_cols, query_ops, query_vals, result_cols,
397                            n_query_cols, n_result_cols, 0, &result)
398                         < 0) {
399                 LM_ERR("unsuccessful sql query\n");
400                 return -2;
401         }
402
403         if(result == NULL)
404                 return -3;
405
406         /* no results from query definitely means no dialog exists */
407         if(result->n <= 0) {
408                 pa_dbf.free_result(pa_db, result);
409                 return 0;
410         }
411
412         // Loop the rows returned from the DB
413         for(i = 0; i < result->n; i++) {
414                 row = &result->rows[i];
415                 row_vals = ROW_VALUES(row);
416                 tmp_db_body.s = (char *)row_vals[rez_body_col].val.string_val;
417                 tmp_db_body.len = strlen(tmp_db_body.s);
418
419                 tmp_db_etag.s = (char *)row_vals[rez_etag_col].val.string_val;
420                 tmp_db_etag.len = strlen(tmp_db_etag.s);
421
422                 if(check_if_dialog(tmp_db_body, &db_is_dialog, &db_dialog_id) == 0) {
423                         // If ID from DB matches the one we supplied
424                         if(db_dialog_id && !strcmp(db_dialog_id, dialog_id)) {
425                                 old_presentity.domain = presentity->domain;
426                                 old_presentity.user = presentity->user;
427                                 old_presentity.event = presentity->event;
428                                 old_presentity.etag = tmp_db_etag;
429
430                                 LM_DBG("Presentity found - deleting it\n");
431
432                                 if(delete_presentity(&old_presentity, NULL) < 0) {
433                                         LM_ERR("failed to delete presentity\n");
434                                 }
435
436                                 pa_dbf.free_result(pa_db, result);
437                                 result = NULL;
438                                 free(db_dialog_id);
439                                 db_dialog_id = NULL;
440
441                                 return 1;
442                         }
443
444                         free(db_dialog_id);
445                         db_dialog_id = NULL;
446                 }
447         }
448
449         pa_dbf.free_result(pa_db, result);
450         result = NULL;
451         return 0;
452 }
453
454 /**
455  * check if the states of all related dialogs match vstate
456  */
457 int ps_match_dialog_state(presentity_t *presentity, char *vstate)
458 {
459         db_key_t query_cols[13], result_cols[6];
460         db_op_t query_ops[13];
461         db_val_t query_vals[13];
462         int n_query_cols = 0;
463         int rez_body_col = 0, n_result_cols = 0;
464         db1_res_t *result = NULL;
465         db_row_t *row = NULL;
466         db_val_t *row_vals = NULL;
467         int db_is_dialog = 0;
468         str tmp_db_body;
469         int i = 0, rmatch = 0;
470
471         query_cols[n_query_cols] = &str_domain_col;
472         query_ops[n_query_cols] = OP_EQ;
473         query_vals[n_query_cols].type = DB1_STR;
474         query_vals[n_query_cols].nul = 0;
475         query_vals[n_query_cols].val.str_val = presentity->domain;
476         n_query_cols++;
477
478         query_cols[n_query_cols] = &str_username_col;
479         query_ops[n_query_cols] = OP_EQ;
480         query_vals[n_query_cols].type = DB1_STR;
481         query_vals[n_query_cols].nul = 0;
482         query_vals[n_query_cols].val.str_val = presentity->user;
483         n_query_cols++;
484
485         query_cols[n_query_cols] = &str_event_col;
486         query_ops[n_query_cols] = OP_EQ;
487         query_vals[n_query_cols].type = DB1_STR;
488         query_vals[n_query_cols].nul = 0;
489         query_vals[n_query_cols].val.str_val = presentity->event->name;
490         n_query_cols++;
491
492         query_cols[n_query_cols] = &str_etag_col;
493         query_ops[n_query_cols] = OP_EQ;
494         query_vals[n_query_cols].type = DB1_STR;
495         query_vals[n_query_cols].nul = 0;
496         query_vals[n_query_cols].val.str_val = presentity->etag;
497         n_query_cols++;
498
499         result_cols[rez_body_col = n_result_cols++] = &str_body_col;
500
501         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
502                 LM_ERR("unsuccessful sql use table\n");
503                 return -1;
504         }
505
506         if(pa_dbf.query(pa_db, query_cols, query_ops, query_vals, result_cols,
507                            n_query_cols, n_result_cols, 0, &result)
508                         < 0) {
509                 LM_ERR("unsuccessful sql query\n");
510                 return -2;
511         }
512
513         if(result == NULL)
514                 return -3;
515
516         /* no results from query definitely means no dialog exists */
517         if(result->n <= 0) {
518                 pa_dbf.free_result(pa_db, result);
519                 return 0;
520         }
521
522         rmatch = 0;
523         // Loop the rows returned from the DB
524         for(i = 0; i < result->n; i++) {
525                 row = &result->rows[i];
526                 row_vals = ROW_VALUES(row);
527                 tmp_db_body.s = (char *)row_vals[rez_body_col].val.string_val;
528                 tmp_db_body.len = strlen(tmp_db_body.s);
529
530                 rmatch = ps_match_dialog_state_from_body(
531                                 tmp_db_body, &db_is_dialog, vstate);
532
533                 if(rmatch == 1) {
534                         /* having a full match */
535                         pa_dbf.free_result(pa_db, result);
536                         result = NULL;
537                         return rmatch;
538                 }
539         }
540
541         pa_dbf.free_result(pa_db, result);
542         result = NULL;
543         return rmatch;
544 }
545
546 static int ps_db_update_presentity(sip_msg_t *msg, presentity_t *presentity,
547                 str *body, int new_t, int *sent_reply, char *sphere, str *etag_override,
548                 str *ruid, int replace)
549 {
550         db_key_t query_cols[14], rquery_cols[2], update_keys[9], result_cols[7];
551         db_op_t query_ops[14], rquery_ops[2];
552         db_val_t query_vals[14], rquery_vals[2], update_vals[9];
553         db1_res_t *result = NULL;
554         int n_query_cols = 0;
555         int n_rquery_cols = 0;
556         int n_update_cols = 0;
557         char *dot = NULL;
558         str etag = {0, 0};
559         str cur_etag = {0, 0};
560         str *rules_doc = NULL;
561         str pres_uri = {0, 0};
562         int rez_body_col, rez_sender_col, rez_ruid_col, n_result_cols = 0;
563         db_row_t *row = NULL;
564         db_val_t *row_vals = NULL;
565         str old_body, sender;
566         int is_dialog = 0, bla_update_publish = 1;
567         int affected_rows = 0;
568         int ret = -1;
569         int db_record_exists = 0;
570         int num_watchers = 0;
571         char *old_dialog_id = NULL, *dialog_id = NULL;
572         str cur_ruid = {0, 0};
573         str p_ruid = {0, 0};
574
575         if(sent_reply)
576                 *sent_reply = 0;
577         if(pres_notifier_processes == 0 && presentity->event->req_auth) {
578                 /* get rules_document */
579                 if(presentity->event->get_rules_doc(
580                                    &presentity->user, &presentity->domain, &rules_doc)
581                                 < 0) {
582                         LM_ERR("getting rules doc\n");
583                         goto error;
584                 }
585         }
586
587         if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri) < 0) {
588                 LM_ERR("constructing uri from user and domain\n");
589                 goto error;
590         }
591
592
593         query_cols[n_query_cols] = &str_domain_col;
594         query_ops[n_query_cols] = OP_EQ;
595         query_vals[n_query_cols].type = DB1_STR;
596         query_vals[n_query_cols].nul = 0;
597         query_vals[n_query_cols].val.str_val = presentity->domain;
598         n_query_cols++;
599
600         query_cols[n_query_cols] = &str_username_col;
601         query_ops[n_query_cols] = OP_EQ;
602         query_vals[n_query_cols].type = DB1_STR;
603         query_vals[n_query_cols].nul = 0;
604         query_vals[n_query_cols].val.str_val = presentity->user;
605         n_query_cols++;
606
607         query_cols[n_query_cols] = &str_event_col;
608         query_ops[n_query_cols] = OP_EQ;
609         query_vals[n_query_cols].type = DB1_STR;
610         query_vals[n_query_cols].nul = 0;
611         query_vals[n_query_cols].val.str_val = presentity->event->name;
612         n_query_cols++;
613
614         query_cols[n_query_cols] = &str_etag_col;
615         query_ops[n_query_cols] = OP_EQ;
616         query_vals[n_query_cols].type = DB1_STR;
617         query_vals[n_query_cols].nul = 0;
618         query_vals[n_query_cols].val.str_val = presentity->etag;
619         n_query_cols++;
620
621         result_cols[rez_body_col = n_result_cols++] = &str_body_col;
622         result_cols[rez_sender_col = n_result_cols++] = &str_sender_col;
623         result_cols[rez_ruid_col = n_result_cols++] = &str_ruid_col;
624
625         if(new_t) {
626                 LM_DBG("new presentity with etag %.*s\n", presentity->etag.len,
627                                 presentity->etag.s);
628
629                 if(ruid) {
630                         /* use the provided ruid */
631                         p_ruid = *ruid;
632                 } else {
633                         /* generate a new ruid */
634                         if(sruid_next(&pres_sruid) < 0)
635                                 goto error;
636                         p_ruid = pres_sruid.uid;
637                 }
638
639                 /* insert new record in hash_table */
640
641                 if(publ_cache_mode==PS_PCACHE_HYBRID
642                                 && insert_phtable(
643                                                    &pres_uri, presentity->event->evp->type, sphere)
644                                                    < 0) {
645                         LM_ERR("inserting record in hash table\n");
646                         goto error;
647                 }
648
649                 LM_DBG("new htable record added\n");
650                 if(presentity->expires == -1) {
651                         replace = 1;
652                 }
653
654                 /* insert new record into database */
655                 query_cols[n_query_cols] = &str_sender_col;
656                 query_vals[n_query_cols].type = DB1_STR;
657                 query_vals[n_query_cols].nul = 0;
658                 if(presentity->sender) {
659                         query_vals[n_query_cols].val.str_val.s = presentity->sender->s;
660                         query_vals[n_query_cols].val.str_val.len = presentity->sender->len;
661                 } else {
662                         query_vals[n_query_cols].val.str_val.s = "";
663                         query_vals[n_query_cols].val.str_val.len = 0;
664                 }
665                 n_query_cols++;
666
667                 query_cols[n_query_cols] = &str_body_col;
668                 query_vals[n_query_cols].type = DB1_BLOB;
669                 query_vals[n_query_cols].nul = 0;
670                 query_vals[n_query_cols].val.str_val = *body;
671                 n_query_cols++;
672
673                 query_cols[n_query_cols] = &str_received_time_col;
674                 query_vals[n_query_cols].type = DB1_INT;
675                 query_vals[n_query_cols].nul = 0;
676                 query_vals[n_query_cols].val.int_val = presentity->received_time;
677                 n_query_cols++;
678
679                 query_cols[n_query_cols] = &str_priority_col;
680                 query_vals[n_query_cols].type = DB1_INT;
681                 query_vals[n_query_cols].nul = 0;
682                 query_vals[n_query_cols].val.int_val = presentity->priority;
683                 n_query_cols++;
684
685                 query_cols[n_query_cols] = &str_ruid_col;
686                 query_vals[n_query_cols].type = DB1_STR;
687                 query_vals[n_query_cols].nul = 0;
688                 query_vals[n_query_cols].val.str_val = p_ruid;
689                 n_query_cols++;
690
691                 if(!replace) {
692                         /* A real PUBLISH */
693                         query_cols[n_query_cols] = &str_expires_col;
694                         query_vals[n_query_cols].type = DB1_INT;
695                         query_vals[n_query_cols].nul = 0;
696                         query_vals[n_query_cols].val.int_val =
697                                         presentity->expires + (int)time(NULL);
698                         n_query_cols++;
699
700                         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
701                                 LM_ERR("unsuccessful use_table\n");
702                                 goto error;
703                         }
704
705                         if(pa_dbf.start_transaction) {
706                                 if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
707                                         LM_ERR("in start_transaction\n");
708                                         goto error;
709                                 }
710                         }
711                         if(presentity->event->evp->type == EVENT_DIALOG) {
712                                 check_if_dialog(*body, &is_dialog, &dialog_id);
713                                 if(dialog_id) {
714                                         if(delete_presentity_if_dialog_id_exists(
715                                                            presentity, dialog_id)
716                                                         < 0) {
717                                                 free(dialog_id);
718                                                 dialog_id = NULL;
719                                                 goto error;
720                                         }
721
722                                         free(dialog_id);
723                                         dialog_id = NULL;
724                                 }
725                         }
726                         LM_DBG("inserting %d cols into table\n", n_query_cols);
727
728                         if(pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) {
729                                 LM_ERR("inserting new record in database\n");
730                                 goto error;
731                         }
732                 } else {
733                         /* A hard-state PUBLISH */
734                         query_cols[n_query_cols] = &str_expires_col;
735                         query_vals[n_query_cols].type = DB1_INT;
736                         query_vals[n_query_cols].nul = 0;
737                         query_vals[n_query_cols].val.int_val = -1;
738                         if(presentity->expires != -1) {
739                                 query_vals[n_query_cols].val.int_val =
740                                                 presentity->expires + (int)time(NULL);
741                         }
742                         n_query_cols++;
743
744                         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
745                                 LM_ERR("unsuccessful use_table\n");
746                                 goto error;
747                         }
748
749                         if(pa_dbf.replace == NULL) {
750                                 LM_ERR("replace is required for pidf-manipulation support\n");
751                                 goto error;
752                         }
753
754                         if(pa_dbf.start_transaction) {
755                                 if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
756                                         LM_ERR("in start_transaction\n");
757                                         goto error;
758                                 }
759                         }
760
761
762                         if(pa_dbf.replace(pa_db, query_cols, query_vals, n_query_cols, 4, 0)
763                                         < 0) {
764                                 LM_ERR("replacing record in database\n");
765                                 goto error;
766                         }
767                 }
768
769                 if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
770                         LM_ERR("sending 200OK\n");
771                         goto error;
772                 }
773                 if(sent_reply)
774                         *sent_reply = 1;
775                 goto send_notify;
776         } else {
777                 LM_DBG("updating existing presentity with etag %.*s\n",
778                                 presentity->etag.len, presentity->etag.s);
779
780                 if(ruid) {
781                         p_ruid = *ruid;
782
783                         rquery_cols[n_rquery_cols] = &str_ruid_col;
784                         rquery_ops[n_rquery_cols] = OP_EQ;
785                         rquery_vals[n_rquery_cols].type = DB1_STR;
786                         rquery_vals[n_rquery_cols].nul = 0;
787                         rquery_vals[n_rquery_cols].val.str_val = p_ruid;
788                         n_rquery_cols++;
789
790                         // TODO: check for out-of-sequence updates
791                 }
792
793                 if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
794                         LM_ERR("unsuccessful sql use table\n");
795                         goto error;
796                 }
797
798                 if(pa_dbf.start_transaction) {
799                         if(pa_dbf.start_transaction(pa_db, pres_db_table_lock) < 0) {
800                                 LM_ERR("in start_transaction\n");
801                                 goto error;
802                         }
803                 }
804
805                 if(EVENT_DIALOG_SLA(presentity->event->evp)) {
806
807                         if(pa_dbf.query(pa_db, ruid ? rquery_cols : query_cols,
808                                            ruid ? rquery_ops : query_ops,
809                                            ruid ? rquery_vals : query_vals, result_cols,
810                                            ruid ? n_rquery_cols : n_query_cols, n_result_cols, 0,
811                                            &result)
812                                         < 0) {
813                                 LM_ERR("unsuccessful sql query\n");
814                                 goto error;
815                         }
816                         if(result == NULL)
817                                 goto error;
818
819                         if(!(result->n > 0))
820                                 goto send_412;
821
822                         db_record_exists = 1;
823                         /* analize if previous body has a dialog */
824                         row = &result->rows[0];
825                         row_vals = ROW_VALUES(row);
826
827                         /* store current ruid if we don't already know it */
828                         if(!p_ruid.s && row_vals[rez_ruid_col].val.string_val) {
829                                 cur_ruid.len =
830                                                 strlen((char *)row_vals[rez_ruid_col].val.string_val);
831                                 cur_ruid.s = (char *)pkg_malloc(sizeof(char) * cur_ruid.len);
832                                 if(!cur_ruid.s) {
833                                         LM_ERR("no private memory\n");
834                                         goto error;
835                                 }
836                                 memcpy(cur_ruid.s,
837                                                 (char *)row_vals[rez_ruid_col].val.string_val,
838                                                 cur_ruid.len);
839                                 p_ruid = cur_ruid;
840                         }
841
842                         old_body.s = (char *)row_vals[rez_body_col].val.string_val;
843                         old_body.len = strlen(old_body.s);
844                         if(check_if_dialog(*body, &is_dialog, &dialog_id) < 0) {
845                                 LM_ERR("failed to check if dialog stored\n");
846                                 if(dialog_id) {
847                                         free(dialog_id);
848                                         dialog_id = NULL;
849                                 }
850                                 goto error;
851                         }
852
853                         free(dialog_id);
854
855                         if(is_dialog == 1) /* if the new body has a dialog - overwrite */
856                         {
857                                 goto after_dialog_check;
858                         }
859
860                         if(check_if_dialog(old_body, &is_dialog, &old_dialog_id) < 0) {
861                                 LM_ERR("failed to check if dialog stored\n");
862                                 if(old_dialog_id) {
863                                         free(old_dialog_id);
864                                         old_dialog_id = NULL;
865                                 }
866                                 goto error;
867                         }
868
869                         /* if the old body has no dialog - overwrite */
870                         if(is_dialog == 0) {
871                                 if(old_dialog_id) {
872                                         free(old_dialog_id);
873                                         old_dialog_id = NULL;
874                                 }
875                                 goto after_dialog_check;
876                         }
877
878                         if(old_dialog_id) {
879                                 free(old_dialog_id);
880                                 old_dialog_id = NULL;
881                         }
882
883                         sender.s = (char *)row_vals[rez_sender_col].val.string_val;
884                         sender.len = strlen(sender.s);
885
886                         LM_DBG("old_sender = %.*s\n", sender.len, sender.s);
887                         if(presentity->sender) {
888                                 if(!(presentity->sender->len == sender.len
889                                                    && presence_sip_uri_match(
890                                                                           presentity->sender, &sender)
891                                                                           == 0))
892                                         bla_update_publish = 0;
893                         }
894                 after_dialog_check:
895                         pa_dbf.free_result(pa_db, result);
896                         result = NULL;
897                 }
898
899                 if(presentity->expires <= 0) {
900
901                         if(!db_record_exists) {
902                                 if(pa_dbf.query(pa_db, ruid ? rquery_cols : query_cols,
903                                                    ruid ? rquery_ops : query_ops,
904                                                    ruid ? rquery_vals : query_vals, result_cols,
905                                                    ruid ? n_rquery_cols : n_query_cols, n_result_cols,
906                                                    0, &result)
907                                                 < 0) {
908                                         LM_ERR("unsuccessful sql query\n");
909                                         goto error;
910                                 }
911                                 if(result == NULL)
912                                         goto error;
913
914                                 if(!(result->n > 0))
915                                         goto send_412;
916
917                                 db_record_exists = 1;
918
919                                 row = &result->rows[0];
920                                 row_vals = ROW_VALUES(row);
921
922                                 /* store current ruid if we don't already know it */
923                                 if(!p_ruid.s && row_vals[rez_ruid_col].val.string_val) {
924                                         cur_ruid.len = strlen(
925                                                         (char *)row_vals[rez_ruid_col].val.string_val);
926                                         cur_ruid.s =
927                                                         (char *)pkg_malloc(sizeof(char) * cur_ruid.len);
928                                         if(!cur_ruid.s) {
929                                                 LM_ERR("no private memory\n");
930                                                 goto error;
931                                         }
932                                         memcpy(cur_ruid.s,
933                                                         (char *)row_vals[rez_ruid_col].val.string_val,
934                                                         cur_ruid.len);
935                                         p_ruid = cur_ruid;
936                                 }
937
938                                 pa_dbf.free_result(pa_db, result);
939                                 result = NULL;
940                         }
941
942                         if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
943                                 LM_ERR("sending 200OK reply\n");
944                                 goto error;
945                         }
946                         if(sent_reply)
947                                 *sent_reply = 1;
948
949                         if(pres_notifier_processes > 0) {
950                                 if((num_watchers = publ_notify_notifier(
951                                                         pres_uri, presentity->event))
952                                                 < 0) {
953                                         LM_ERR("updating watcher records\n");
954                                         goto error;
955                                 }
956
957                                 if(num_watchers > 0) {
958                                         if(mark_presentity_for_delete(presentity, &p_ruid) < 0) {
959                                                 LM_ERR("Marking presentities\n");
960                                                 goto error;
961                                         }
962                                 }
963                         } else {
964                                 if(publ_notify(presentity, pres_uri, body, &presentity->etag,
965                                                    rules_doc)
966                                                 < 0) {
967                                         LM_ERR("while sending notify\n");
968                                         goto error;
969                                 }
970                         }
971
972                         if(pres_notifier_processes == 0 || num_watchers == 0) {
973                                 if(delete_presentity(presentity, &p_ruid) < 0) {
974                                         LM_ERR("Deleting presentity\n");
975                                         goto error;
976                                 }
977
978                                 LM_DBG("deleted from db %.*s\n", presentity->user.len,
979                                                 presentity->user.s);
980                         }
981
982                         /* delete from hash table */
983                         if(publ_cache_mode == PS_PCACHE_HYBRID
984                                         && delete_phtable(&pres_uri, presentity->event->evp->type)
985                                                            < 0) {
986                                 LM_ERR("deleting record from hash table\n");
987                                 goto error;
988                         }
989                         goto done;
990                 }
991
992                 n_update_cols = 0;
993                 /* if event dialog and is_dialog -> if sender not the same as
994                  * old sender do not overwrite */
995                 if(EVENT_DIALOG_SLA(presentity->event->evp)
996                                 && bla_update_publish == 0) {
997                         LM_DBG("drop Publish for BLA from a different sender that"
998                                    " wants to overwrite an existing dialog\n");
999                         LM_DBG("sender = %.*s\n", presentity->sender->len,
1000                                         presentity->sender->s);
1001                         if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1002                                 LM_ERR("sending 200OK reply\n");
1003                                 goto error;
1004                         }
1005                         if(sent_reply)
1006                                 *sent_reply = 1;
1007                         goto done;
1008                 }
1009
1010                 if(presentity->event->etag_not_new == 0 || etag_override) {
1011                         if(etag_override) {
1012                                 /* use the supplied etag */
1013                                 LM_DBG("updating with supplied etag %.*s\n", etag_override->len,
1014                                                 etag_override->s);
1015                                 cur_etag = *etag_override;
1016                                 goto after_etag_generation;
1017                         }
1018
1019                         /* generate another etag */
1020                         unsigned int publ_nr;
1021                         str str_publ_nr = {0, 0};
1022
1023                         dot = presentity->etag.s + presentity->etag.len;
1024                         while(*dot != '.' && str_publ_nr.len < presentity->etag.len) {
1025                                 str_publ_nr.len++;
1026                                 dot--;
1027                         }
1028                         if(str_publ_nr.len == presentity->etag.len) {
1029                                 LM_ERR("wrong etag\n");
1030                                 goto error;
1031                         }
1032                         str_publ_nr.s = dot + 1;
1033                         str_publ_nr.len--;
1034
1035                         if(str2int(&str_publ_nr, &publ_nr) < 0) {
1036                                 LM_ERR("converting string to int\n");
1037                                 goto error;
1038                         }
1039                         etag.s = generate_ETag(publ_nr + 1);
1040                         if(etag.s == NULL) {
1041                                 LM_ERR("while generating etag\n");
1042                                 goto error;
1043                         }
1044                         etag.len = (strlen(etag.s));
1045
1046                         cur_etag = etag;
1047
1048                 after_etag_generation:
1049
1050                         update_keys[n_update_cols] = &str_etag_col;
1051                         update_vals[n_update_cols].type = DB1_STR;
1052                         update_vals[n_update_cols].nul = 0;
1053                         update_vals[n_update_cols].val.str_val = cur_etag;
1054                         n_update_cols++;
1055
1056                 } else
1057                         cur_etag = presentity->etag;
1058
1059                 if(presentity->event->evp->type == EVENT_DIALOG) {
1060                         if(ps_match_dialog_state(presentity, "terminated") == 1) {
1061                                 LM_WARN("Trying to update an already terminated state."
1062                                                 " Skipping update.\n");
1063
1064                                 /* send 200OK */
1065                                 if(publ_send200ok(msg, presentity->expires, cur_etag) < 0) {
1066                                         LM_ERR("sending 200OK reply\n");
1067                                         goto error;
1068                                 }
1069                                 if(sent_reply)
1070                                         *sent_reply = 1;
1071
1072                                 goto done;
1073                         }
1074                 }
1075
1076                 update_keys[n_update_cols] = &str_expires_col;
1077                 update_vals[n_update_cols].type = DB1_INT;
1078                 update_vals[n_update_cols].nul = 0;
1079                 update_vals[n_update_cols].val.int_val =
1080                                 presentity->expires + (int)time(NULL);
1081                 n_update_cols++;
1082
1083                 update_keys[n_update_cols] = &str_received_time_col;
1084                 update_vals[n_update_cols].type = DB1_INT;
1085                 update_vals[n_update_cols].nul = 0;
1086                 update_vals[n_update_cols].val.int_val = presentity->received_time;
1087                 n_update_cols++;
1088
1089                 update_keys[n_update_cols] = &str_priority_col;
1090                 update_vals[n_update_cols].type = DB1_INT;
1091                 update_vals[n_update_cols].nul = 0;
1092                 update_vals[n_update_cols].val.int_val = presentity->priority;
1093                 n_update_cols++;
1094
1095                 if(body && body->s) {
1096                         update_keys[n_update_cols] = &str_body_col;
1097                         update_vals[n_update_cols].type = DB1_BLOB;
1098                         update_vals[n_update_cols].nul = 0;
1099                         update_vals[n_update_cols].val.str_val = *body;
1100                         n_update_cols++;
1101
1102                         /* updated stored sphere */
1103                         if(pres_sphere_enable
1104                                         && presentity->event->evp->type == EVENT_PRESENCE) {
1105                                 if(publ_cache_mode == PS_PCACHE_HYBRID
1106                                                 && update_phtable(presentity, &pres_uri, body) < 0) {
1107                                         LM_ERR("failed to update sphere for presentity\n");
1108                                         goto error;
1109                                 }
1110                         }
1111                 }
1112
1113                 if(presentity->sender) {
1114                         update_keys[n_update_cols] = &str_sender_col;
1115                         update_vals[n_update_cols].type = DB1_STR;
1116                         update_vals[n_update_cols].nul = 0;
1117                         update_vals[n_update_cols].val.str_val = *presentity->sender;
1118                         n_update_cols++;
1119                 }
1120
1121                 /* if there is no support for affected_rows and no previous query has been done,
1122                  * or dmq replication is enabled and we don't already know the ruid, do query */
1123                 if((!pa_dbf.affected_rows && !db_record_exists)
1124                                 || (pres_enable_dmq > 0 && !p_ruid.s)) {
1125                         if(pa_dbf.query(pa_db, ruid ? rquery_cols : query_cols,
1126                                            ruid ? rquery_ops : query_ops,
1127                                            ruid ? rquery_vals : query_vals, result_cols,
1128                                            ruid ? n_rquery_cols : n_query_cols, n_result_cols, 0,
1129                                            &result)
1130                                         < 0) {
1131                                 LM_ERR("unsuccessful sql query\n");
1132                                 goto error;
1133                         }
1134                         if(result == NULL)
1135                                 goto error;
1136
1137                         if(!(result->n > 0))
1138                                 goto send_412;
1139
1140                         db_record_exists = 1;
1141                         affected_rows = result->n;
1142
1143                         row = &result->rows[0];
1144                         row_vals = ROW_VALUES(row);
1145
1146                         /* store current ruid if we don't already know it */
1147                         if(!p_ruid.s && row_vals[rez_ruid_col].val.string_val) {
1148                                 cur_ruid.len =
1149                                                 strlen((char *)row_vals[rez_ruid_col].val.string_val);
1150                                 cur_ruid.s = (char *)pkg_malloc(sizeof(char) * cur_ruid.len);
1151                                 if(!cur_ruid.s) {
1152                                         LM_ERR("no private memory\n");
1153                                         goto error;
1154                                 }
1155                                 memcpy(cur_ruid.s,
1156                                                 (char *)row_vals[rez_ruid_col].val.string_val,
1157                                                 cur_ruid.len);
1158                                 p_ruid = cur_ruid;
1159
1160                                 LM_DBG("existing ruid %.*s\n", p_ruid.len, p_ruid.s);
1161                         }
1162
1163                         pa_dbf.free_result(pa_db, result);
1164                         result = NULL;
1165                 }
1166
1167                 if(pa_dbf.update(pa_db, ruid ? rquery_cols : query_cols,
1168                                    ruid ? rquery_ops : query_ops,
1169                                    ruid ? rquery_vals : query_vals, update_keys, update_vals,
1170                                    ruid ? n_rquery_cols : n_query_cols, n_update_cols)
1171                                 < 0) {
1172                         LM_ERR("updating published info in database\n");
1173                         goto error;
1174                 }
1175
1176                 if(pa_dbf.affected_rows && !db_record_exists) {
1177                         if((affected_rows = pa_dbf.affected_rows(pa_db)) < 0) {
1178                                 LM_ERR("unsuccessful sql affected rows operation");
1179                                 goto error;
1180                         }
1181
1182                         LM_DBG("affected rows after update: %d\n", affected_rows);
1183                 }
1184
1185
1186                 /*if either affected_rows (if exists) or select query show that there is no line in database*/
1187                 if((pa_dbf.affected_rows && !affected_rows && !db_record_exists)
1188                                 || (!pa_dbf.affected_rows && !db_record_exists))
1189                         goto send_412;
1190
1191                 /* send 200OK */
1192                 if(publ_send200ok(msg, presentity->expires, cur_etag) < 0) {
1193                         LM_ERR("sending 200OK reply\n");
1194                         goto error;
1195                 }
1196                 if(sent_reply)
1197                         *sent_reply = 1;
1198
1199                 if(!body)
1200                         goto done;
1201         }
1202
1203 send_notify:
1204
1205         /* send notify with presence information */
1206         if(pres_notifier_processes > 0) {
1207                 if(publ_notify_notifier(pres_uri, presentity->event) < 0) {
1208                         LM_ERR("updating watcher records\n");
1209                         goto error;
1210                 }
1211         } else {
1212                 if(publ_notify(presentity, pres_uri, body, NULL, rules_doc) < 0) {
1213                         LM_ERR("while sending notify\n");
1214                         goto error;
1215                 }
1216         }
1217
1218 done:
1219
1220         if(pres_enable_dmq > 0 && p_ruid.s != NULL) {
1221                 pres_dmq_replicate_presentity(
1222                                 presentity, body, new_t, &cur_etag, sphere, &p_ruid, NULL);
1223         }
1224
1225         if(etag.s)
1226                 pkg_free(etag.s);
1227         etag.s = NULL;
1228
1229         if(cur_ruid.s)
1230                 pkg_free(cur_ruid.s);
1231         cur_ruid.s = NULL;
1232
1233         if(rules_doc) {
1234                 if(rules_doc->s)
1235                         pkg_free(rules_doc->s);
1236                 pkg_free(rules_doc);
1237                 rules_doc = NULL;
1238         }
1239         if(pres_uri.s) {
1240                 pkg_free(pres_uri.s);
1241                 pres_uri.s = NULL;
1242         }
1243
1244         if(pa_dbf.end_transaction) {
1245                 if(pa_dbf.end_transaction(pa_db) < 0) {
1246                         LM_ERR("in end_transaction\n");
1247                         goto error;
1248                 }
1249         }
1250
1251         return 0;
1252
1253 send_412:
1254
1255         if(!ruid) {
1256                 LM_ERR("No E_Tag match %*s\n", presentity->etag.len,
1257                                 presentity->etag.s);
1258         } else {
1259                 LM_ERR("No ruid match %*s\n", ruid->len, ruid->s);
1260         }
1261
1262         if(msg != NULL) {
1263                 if(slb.freply(msg, 412, &pu_412_rpl) < 0) {
1264                         LM_ERR("sending '412 Conditional request failed' reply\n");
1265                         goto error;
1266                 }
1267         }
1268         if(sent_reply)
1269                 *sent_reply = 1;
1270         ret = 0;
1271
1272 error:
1273         if(result)
1274                 pa_dbf.free_result(pa_db, result);
1275         if(etag.s)
1276                 pkg_free(etag.s);
1277         if(rules_doc) {
1278                 if(rules_doc->s)
1279                         pkg_free(rules_doc->s);
1280                 pkg_free(rules_doc);
1281         }
1282         if(pres_uri.s) {
1283                 pkg_free(pres_uri.s);
1284         }
1285         if(cur_ruid.s)
1286                 pkg_free(cur_ruid.s);
1287
1288         if(pa_dbf.abort_transaction) {
1289                 if(pa_dbf.abort_transaction(pa_db) < 0) {
1290                         LM_ERR("in abort_transaction\n");
1291                 }
1292         }
1293
1294         return ret;
1295 }
1296
1297 static int ps_cache_update_presentity(sip_msg_t *msg, presentity_t *presentity,
1298                 str *body, int new_t, int *sent_reply, char *sphere, str *etag_override,
1299                 str *ruid, int replace)
1300 {
1301         char *dot = NULL;
1302         str etag = STR_NULL;
1303         str crt_etag = STR_NULL;
1304         str *rules_doc = NULL;
1305         str pres_uri = STR_NULL;
1306         str old_body = STR_NULL;
1307         str sender = STR_NULL;
1308         int is_dialog = 0;
1309         int bla_update_publish = 1;
1310         int affected_rows = 0;
1311         int ret = -1;
1312         int cache_record_exists = 0;
1313         int num_watchers = 0;
1314         char *old_dialog_id = NULL;
1315         char *dialog_id = NULL;
1316         str crt_ruid = STR_NULL;
1317         str p_ruid = STR_NULL;
1318         ps_presentity_t ptc;
1319         ps_presentity_t ptm;
1320         ps_presentity_t *ptx = NULL;
1321
1322         if(sent_reply) {
1323                 *sent_reply = 0;
1324         }
1325         memset(&ptc, 0, sizeof(ps_presentity_t));
1326         memset(&ptm, 0, sizeof(ps_presentity_t));
1327
1328         /* here pres_notifier_processes == 0 -- used for db-only */
1329         if(presentity->event->req_auth) {
1330                 /* get rules_document */
1331                 if(presentity->event->get_rules_doc(
1332                                    &presentity->user, &presentity->domain, &rules_doc)
1333                                 < 0) {
1334                         LM_ERR("getting rules doc\n");
1335                         goto error;
1336                 }
1337         }
1338
1339         if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri) < 0) {
1340                 LM_ERR("constructing uri from user and domain\n");
1341                 goto error;
1342         }
1343
1344         ptc.user = presentity->user;
1345         ptc.domain = presentity->domain;
1346         ptc.event = presentity->event->name;
1347         ptc.etag = presentity->etag;
1348
1349         ptm.user = presentity->user;
1350         ptm.domain = presentity->domain;
1351         ptm.event = presentity->event->name;
1352         ptm.etag = presentity->etag;
1353
1354         if(new_t) {
1355                 LM_DBG("new presentity with etag %.*s\n", presentity->etag.len,
1356                                 presentity->etag.s);
1357
1358                 if(ruid) {
1359                         /* use the provided ruid */
1360                         p_ruid = *ruid;
1361                 } else {
1362                         /* generate a new ruid */
1363                         if(sruid_next(&pres_sruid) < 0)
1364                                 goto error;
1365                         p_ruid = pres_sruid.uid;
1366                 }
1367                 if(presentity->sender) {
1368                         ptc.sender = *presentity->sender;
1369                 } else {
1370                         ptc.sender.s = "";
1371                         ptc.sender.len = 0;
1372                 }
1373                 ptc.body = *body;
1374                 ptc.received_time = presentity->received_time;
1375                 ptc.priority = presentity->priority;
1376                 ptc.ruid = p_ruid;
1377
1378                 LM_DBG("adding new htable record\n");
1379                 if(presentity->expires == -1) {
1380                         replace = 1;
1381                 }
1382                 if(!replace) {
1383                         /* A real PUBLISH */
1384                         ptc.expires = presentity->expires + (int)time(NULL);
1385                         if(presentity->event->evp->type == EVENT_DIALOG) {
1386                                 check_if_dialog(*body, &is_dialog, &dialog_id);
1387                                 if(dialog_id) {
1388                                         if(delete_presentity_if_dialog_id_exists(
1389                                                            presentity, dialog_id)
1390                                                         < 0) {
1391                                                 free(dialog_id);
1392                                                 dialog_id = NULL;
1393                                                 goto error;
1394                                         }
1395
1396                                         free(dialog_id);
1397                                         dialog_id = NULL;
1398                                 }
1399                         }
1400                         LM_DBG("inserting presentity into hash table\n");
1401                         if(ps_ptable_insert(&ptc) < 0) {
1402                                 LM_ERR("inserting new record in memory\n");
1403                                 goto error;
1404                         }
1405                 } else {
1406                         /* A hard-state PUBLISH */
1407                         ptc.expires = -1;
1408                         if(presentity->expires != -1) {
1409                                 ptc.expires = presentity->expires + (int)time(NULL);
1410                         }
1411                         /* update/replace in memory */
1412                         if(ps_ptable_replace(&ptm, &ptc) <0) {
1413                                 LM_ERR("replacing record in database\n");
1414                                 goto error;
1415                         }
1416                 }
1417                 if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1418                         LM_ERR("sending 200OK\n");
1419                         goto error;
1420                 }
1421                 if(sent_reply) {
1422                         *sent_reply = 1;
1423                 }
1424                 goto send_notify;
1425         } else {
1426                 LM_DBG("updating existing presentity with etag %.*s\n",
1427                                 presentity->etag.len, presentity->etag.s);
1428
1429                 if(ruid) {
1430                         p_ruid = *ruid;
1431                 }
1432                 if(EVENT_DIALOG_SLA(presentity->event->evp)) {
1433                         ptx = ps_ptable_get_item(&ptm.user, &ptm.domain, &ptm.event,
1434                                         &ptm.etag);
1435                         if(ptx == NULL) {
1436                                 LM_DBG("presentity record not found\n");
1437                                 goto send_412;
1438                         }
1439                         cache_record_exists = 1;
1440                         if(!p_ruid.s && ptx->ruid.s) {
1441                                 crt_ruid.len = ptx->ruid.len;
1442                                 crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1443                                 if(!crt_ruid.s) {
1444                                         LM_ERR("no private memory\n");
1445                                         goto error;
1446                                 }
1447                                 memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1448                                 p_ruid = crt_ruid;
1449                         }
1450
1451                         old_body = ptx->body;
1452                         if(check_if_dialog(*body, &is_dialog, &dialog_id) < 0) {
1453                                 LM_ERR("failed to check if dialog stored\n");
1454                                 if(dialog_id) {
1455                                         free(dialog_id);
1456                                         dialog_id = NULL;
1457                                 }
1458                                 goto error;
1459                         }
1460
1461                         free(dialog_id);
1462
1463                         if(is_dialog == 1) {
1464                                 /* if the new body has a dialog - overwrite */
1465                                 goto after_dialog_check;
1466                         }
1467                         if(check_if_dialog(old_body, &is_dialog, &old_dialog_id) < 0) {
1468                                 LM_ERR("failed to check if dialog stored\n");
1469                                 if(old_dialog_id) {
1470                                         free(old_dialog_id);
1471                                         old_dialog_id = NULL;
1472                                 }
1473                                 goto error;
1474                         }
1475
1476                         /* if the old body has no dialog - overwrite */
1477                         if(is_dialog == 0) {
1478                                 if(old_dialog_id) {
1479                                         free(old_dialog_id);
1480                                         old_dialog_id = NULL;
1481                                 }
1482                                 goto after_dialog_check;
1483                         }
1484
1485                         if(old_dialog_id) {
1486                                 free(old_dialog_id);
1487                                 old_dialog_id = NULL;
1488                         }
1489
1490                         sender = ptx->sender;
1491
1492                         LM_DBG("old_sender = %.*s\n", sender.len, sender.s);
1493                         if(presentity->sender) {
1494                                 if(!(presentity->sender->len == sender.len
1495                                                    && presence_sip_uri_match(
1496                                                                           presentity->sender, &sender)
1497                                                                           == 0))
1498                                         bla_update_publish = 0;
1499                         }
1500 after_dialog_check:
1501                         ps_presentity_free(ptx, 1);
1502                         ptx = NULL;
1503                 }
1504
1505                 if(presentity->expires <= 0) {
1506
1507                         if(!cache_record_exists) {
1508                                 ptx = ps_ptable_get_item(&ptm.user, &ptm.domain, &ptm.event,
1509                                                 &ptm.etag);
1510                                 if(ptx == NULL) {
1511                                         LM_DBG("presentity record not found\n");
1512                                         goto send_412;
1513                                 }
1514                                 cache_record_exists = 1;
1515                                 if(!p_ruid.s && ptx->ruid.s) {
1516                                         crt_ruid.len = ptx->ruid.len;
1517                                         crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1518                                         if(!crt_ruid.s) {
1519                                                 LM_ERR("no private memory\n");
1520                                                 goto error;
1521                                         }
1522                                         memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1523                                         p_ruid = crt_ruid;
1524                                 }
1525                                 ps_presentity_free(ptx, 1);
1526                                 ptx = NULL;
1527                         }
1528                         if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1529                                 LM_ERR("sending 200OK reply\n");
1530                                 goto error;
1531                         }
1532                         if(sent_reply) {
1533                                 *sent_reply = 1;
1534                         }
1535
1536                         if(publ_notify(presentity, pres_uri, body, &presentity->etag,
1537                                                    rules_doc)
1538                                                 < 0) {
1539                                 LM_ERR("while sending notify\n");
1540                                 goto error;
1541                         }
1542                         if(num_watchers == 0) {
1543                                 if(delete_presentity(presentity, &p_ruid) < 0) {
1544                                         LM_ERR("Deleting presentity\n");
1545                                         goto error;
1546                                 }
1547
1548                                 LM_DBG("deleted from db %.*s\n", presentity->user.len,
1549                                                 presentity->user.s);
1550                         }
1551                         goto done;
1552                 }
1553
1554                 /* if event dialog and is_dialog -> if sender not the same as
1555                  * old sender do not overwrite */
1556                 if(EVENT_DIALOG_SLA(presentity->event->evp)
1557                                 && bla_update_publish == 0) {
1558                         LM_DBG("drop Publish for BLA from a different sender that"
1559                                    " wants to overwrite an existing dialog\n");
1560                         LM_DBG("sender = %.*s\n", presentity->sender->len,
1561                                         presentity->sender->s);
1562                         if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1563                                 LM_ERR("sending 200OK reply\n");
1564                                 goto error;
1565                         }
1566                         if(sent_reply)
1567                                 *sent_reply = 1;
1568                         goto done;
1569                 }
1570
1571                 if(presentity->event->etag_not_new == 0 || etag_override) {
1572                         unsigned int publ_nr;
1573                         str str_publ_nr = {0, 0};
1574
1575                         if(etag_override) {
1576                                 /* use the supplied etag */
1577                                 LM_DBG("updating with supplied etag %.*s\n", etag_override->len,
1578                                                 etag_override->s);
1579                                 crt_etag = *etag_override;
1580                                 goto after_etag_generation;
1581                         }
1582
1583                         /* generate another etag */
1584                         LM_DBG("generating a new etag (%d)\n", presentity->event->etag_not_new);
1585
1586                         dot = presentity->etag.s + presentity->etag.len;
1587                         while(*dot != '.' && str_publ_nr.len < presentity->etag.len) {
1588                                 str_publ_nr.len++;
1589                                 dot--;
1590                         }
1591                         if(str_publ_nr.len == presentity->etag.len) {
1592                                 LM_ERR("wrong etag\n");
1593                                 goto error;
1594                         }
1595                         str_publ_nr.s = dot + 1;
1596                         str_publ_nr.len--;
1597
1598                         if(str2int(&str_publ_nr, &publ_nr) < 0) {
1599                                 LM_ERR("converting string to int\n");
1600                                 goto error;
1601                         }
1602                         etag.s = generate_ETag(publ_nr + 1);
1603                         if(etag.s == NULL) {
1604                                 LM_ERR("while generating etag\n");
1605                                 goto error;
1606                         }
1607                         etag.len = (strlen(etag.s));
1608
1609                         crt_etag = etag;
1610
1611 after_etag_generation:
1612                         ptc.etag = crt_etag;
1613                 } else {
1614                         crt_etag = presentity->etag;
1615                 }
1616
1617                 if(presentity->event->evp->type == EVENT_DIALOG) {
1618                         if(ps_match_dialog_state(presentity, "terminated") == 1) {
1619                                 LM_WARN("Trying to update an already terminated state."
1620                                                 " Skipping update.\n");
1621
1622                                 /* send 200OK */
1623                                 if(publ_send200ok(msg, presentity->expires, crt_etag) < 0) {
1624                                         LM_ERR("sending 200OK reply\n");
1625                                         goto error;
1626                                 }
1627                                 if(sent_reply) {
1628                                         *sent_reply = 1;
1629                                 }
1630                                 goto done;
1631                         }
1632                 }
1633
1634                 ptc.expires = presentity->expires + (int)time(NULL);
1635                 ptc.received_time = presentity->received_time;
1636                 ptc.priority = presentity->priority;
1637                 if(body && body->s) {
1638                         ptc.body = *body;
1639                 }
1640                 if(presentity->sender) {
1641                         ptc.sender = *presentity->sender;
1642                 }
1643
1644                 /* if there is no support for affected_rows and no previous query has been done,
1645                  * or dmq replication is enabled and we don't already know the ruid, do query */
1646                 if((!cache_record_exists)
1647                                 || (pres_enable_dmq > 0 && !p_ruid.s)) {
1648                         ptx = ps_ptable_get_item(&ptm.user, &ptm.domain, &ptm.event,
1649                                         &ptm.etag);
1650                         if(ptx == NULL) {
1651                                 LM_DBG("presentity record not found\n");
1652                                 goto send_412;
1653                         }
1654                         cache_record_exists = 1;
1655                         if(!p_ruid.s && ptx->ruid.s) {
1656                                 crt_ruid.len = ptx->ruid.len;
1657                                 crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1658                                 if(!crt_ruid.s) {
1659                                         LM_ERR("no private memory\n");
1660                                         goto error;
1661                                 }
1662                                 memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1663                                 p_ruid = crt_ruid;
1664                         }
1665                         LM_DBG("existing ruid %.*s\n", p_ruid.len, p_ruid.s);
1666                         ps_presentity_free(ptx, 1);
1667                         ptx = NULL;
1668                 }
1669                 affected_rows = ps_ptable_update(&ptm, &ptc);
1670                 if(affected_rows < 0) {
1671                         LM_ERR("updating published info in database\n");
1672                         goto error;
1673                 }
1674                 /* if either affected_rows (if exists) or select query show that there is no line in database*/
1675                 if(affected_rows==0) {
1676                         LM_DBG("no presentity record found to be updated\n");
1677                         goto send_412;
1678                 }
1679
1680                 /* send 200OK */
1681                 if(publ_send200ok(msg, presentity->expires, crt_etag) < 0) {
1682                         LM_ERR("sending 200OK reply\n");
1683                         goto error;
1684                 }
1685                 if(sent_reply) {
1686                         *sent_reply = 1;
1687                 }
1688
1689                 if(!body) {
1690                         goto done;
1691                 }
1692         }
1693
1694 send_notify:
1695
1696         /* send notify with presence information */
1697         if(publ_notify(presentity, pres_uri, body, NULL, rules_doc) < 0) {
1698                 LM_ERR("while sending notify\n");
1699                 goto error;
1700         }
1701
1702 done:
1703
1704         if(pres_enable_dmq > 0 && p_ruid.s != NULL) {
1705                 pres_dmq_replicate_presentity(
1706                                 presentity, body, new_t, &crt_etag, sphere, &p_ruid, NULL);
1707         }
1708
1709         if(etag.s) {
1710                 pkg_free(etag.s);
1711         }
1712         etag.s = NULL;
1713
1714         if(crt_ruid.s) {
1715                 pkg_free(crt_ruid.s);
1716         }
1717         crt_ruid.s = NULL;
1718
1719         if(rules_doc) {
1720                 if(rules_doc->s) {
1721                         pkg_free(rules_doc->s);
1722                 }
1723                 pkg_free(rules_doc);
1724                 rules_doc = NULL;
1725         }
1726         if(pres_uri.s) {
1727                 pkg_free(pres_uri.s);
1728                 pres_uri.s = NULL;
1729         }
1730
1731         return 0;
1732
1733 send_412:
1734
1735         if(!ruid) {
1736                 LM_ERR("No E_Tag match %*s\n", presentity->etag.len,
1737                                 presentity->etag.s);
1738         } else {
1739                 LM_ERR("No ruid match %*s\n", ruid->len, ruid->s);
1740         }
1741
1742         if(msg != NULL) {
1743                 if(slb.freply(msg, 412, &pu_412_rpl) < 0) {
1744                         LM_ERR("sending '412 Conditional request failed' reply\n");
1745                         goto error;
1746                 }
1747         }
1748         if(sent_reply) {
1749                 *sent_reply = 1;
1750         }
1751         ret = 0;
1752
1753 error:
1754         if(ptx) {
1755                 ps_presentity_free(ptx, 1);
1756         }
1757         if(etag.s) {
1758                 pkg_free(etag.s);
1759         }
1760         if(rules_doc) {
1761                 if(rules_doc->s)
1762                         pkg_free(rules_doc->s);
1763                 pkg_free(rules_doc);
1764         }
1765         if(pres_uri.s) {
1766                 pkg_free(pres_uri.s);
1767         }
1768         if(crt_ruid.s) {
1769                 pkg_free(crt_ruid.s);
1770         }
1771
1772         return ret;
1773 }
1774
1775 /**
1776  *
1777  */
1778 int update_presentity(sip_msg_t *msg, presentity_t *presentity, str *body,
1779                 int new_t, int *sent_reply, char *sphere, str *etag_override, str *ruid,
1780                 int replace)
1781 {
1782         if(publ_cache_mode == PS_PCACHE_RECORD) {
1783                 return ps_cache_update_presentity(msg, presentity, body, new_t,
1784                                 sent_reply, sphere, etag_override, ruid, replace);
1785         } else {
1786                 return ps_db_update_presentity(msg, presentity, body, new_t,
1787                                 sent_reply, sphere, etag_override, ruid, replace);
1788         }
1789 }
1790
1791 /**
1792  *
1793  */
1794 int pres_htable_db_restore(void)
1795 {
1796         /* query all records from presentity table and insert records
1797          * in presentity table */
1798         db_key_t result_cols[6];
1799         db1_res_t *result = NULL;
1800         db_row_t *row = NULL;
1801         db_val_t *row_vals;
1802         int i;
1803         str user, domain, ev_str, uri, body;
1804         int n_result_cols = 0;
1805         int user_col, domain_col, event_col, expires_col, body_col = 0;
1806         int event;
1807         event_t ev;
1808         char *sphere = NULL;
1809         static str query_str;
1810
1811         result_cols[user_col = n_result_cols++] = &str_username_col;
1812         result_cols[domain_col = n_result_cols++] = &str_domain_col;
1813         result_cols[event_col = n_result_cols++] = &str_event_col;
1814         result_cols[expires_col = n_result_cols++] = &str_expires_col;
1815         if(pres_sphere_enable) {
1816                 result_cols[body_col = n_result_cols++] = &str_body_col;
1817         }
1818
1819         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
1820                 LM_ERR("unsuccessful use table sql operation\n");
1821                 goto error;
1822         }
1823
1824         query_str = str_username_col;
1825         if(db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, 0, 0, 0, result_cols, 0,
1826                            n_result_cols, &query_str, &result)
1827                         < 0) {
1828                 LM_ERR("querying presentity\n");
1829                 goto error;
1830         }
1831         if(result == NULL)
1832                 goto error;
1833
1834         if(result->n <= 0) {
1835                 pa_dbf.free_result(pa_db, result);
1836                 return 0;
1837         }
1838
1839         do {
1840                 for(i = 0; i < result->n; i++) {
1841                         row = &result->rows[i];
1842                         row_vals = ROW_VALUES(row);
1843
1844                         if(pres_startup_mode != 0
1845                                         && (row_vals[expires_col].val.int_val < (int)time(NULL)))
1846                                 continue;
1847
1848                         sphere = NULL;
1849                         user.s = (char *)row_vals[user_col].val.string_val;
1850                         user.len = strlen(user.s);
1851                         domain.s = (char *)row_vals[domain_col].val.string_val;
1852                         domain.len = strlen(domain.s);
1853                         ev_str.s = (char *)row_vals[event_col].val.string_val;
1854                         ev_str.len = strlen(ev_str.s);
1855
1856                         memset(&ev, 0, sizeof(event_t));
1857                         if(event_parser(ev_str.s, ev_str.len, &ev) < 0) {
1858                                 LM_ERR("parsing event\n");
1859                                 free_event_params(ev.params.list, PKG_MEM_TYPE);
1860                                 goto error;
1861                         }
1862                         event = ev.type;
1863                         free_event_params(ev.params.list, PKG_MEM_TYPE);
1864
1865                         if(uandd_to_uri(user, domain, &uri) < 0) {
1866                                 LM_ERR("constructing uri\n");
1867                                 goto error;
1868                         }
1869                         /* insert in hash_table*/
1870
1871                         if(pres_sphere_enable && event == EVENT_PRESENCE) {
1872                                 body.s = (char *)row_vals[body_col].val.string_val;
1873                                 body.len = strlen(body.s);
1874                                 sphere = extract_sphere(&body);
1875                         }
1876
1877                         if(insert_phtable(&uri, event, sphere) < 0) {
1878                                 LM_ERR("inserting record in presentity hash table");
1879                                 pkg_free(uri.s);
1880                                 if(sphere)
1881                                         pkg_free(sphere);
1882                                 goto error;
1883                         }
1884                         if(sphere)
1885                                 pkg_free(sphere);
1886                         pkg_free(uri.s);
1887                 }
1888         } while((db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1)
1889                         && (RES_ROW_N(result) > 0));
1890
1891         pa_dbf.free_result(pa_db, result);
1892
1893         return 0;
1894
1895 error:
1896         if(result)
1897                 pa_dbf.free_result(pa_db, result);
1898         return -1;
1899 }
1900
1901 char *extract_sphere(str *body)
1902 {
1903
1904         /* check for a rpid sphere element */
1905         xmlDocPtr doc = NULL;
1906         xmlNodePtr node;
1907         char *cont, *sphere = NULL;
1908
1909
1910         doc = xmlParseMemory(body->s, body->len);
1911         if(doc == NULL) {
1912                 LM_ERR("failed to parse xml body\n");
1913                 return NULL;
1914         }
1915
1916         node = xmlNodeGetNodeByName(doc->children, "sphere", "rpid");
1917
1918         if(node == NULL)
1919                 node = xmlNodeGetNodeByName(doc->children, "sphere", "r");
1920
1921         if(node) {
1922                 LM_DBG("found sphere definition\n");
1923                 cont = (char *)xmlNodeGetContent(node);
1924                 if(cont == NULL) {
1925                         LM_ERR("failed to extract sphere node content\n");
1926                         goto error;
1927                 }
1928                 sphere = (char *)pkg_malloc((strlen(cont) + 1) * sizeof(char));
1929                 if(sphere == NULL) {
1930                         xmlFree(cont);
1931                         ERR_MEM(PKG_MEM_STR);
1932                 }
1933                 strcpy(sphere, cont);
1934                 xmlFree(cont);
1935         } else
1936                 LM_DBG("didn't find sphere definition\n");
1937
1938 error:
1939         xmlFreeDoc(doc);
1940
1941         return sphere;
1942 }
1943
1944 xmlNodePtr xmlNodeGetNodeByName(
1945                 xmlNodePtr node, const char *name, const char *ns)
1946 {
1947         xmlNodePtr cur = node;
1948         while(cur) {
1949                 xmlNodePtr match = NULL;
1950                 if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0) {
1951                         if(!ns
1952                                         || (cur->ns
1953                                                            && xmlStrcasecmp(
1954                                                                                   cur->ns->prefix, (unsigned char *)ns)
1955                                                                                   == 0))
1956                                 return cur;
1957                 }
1958                 match = xmlNodeGetNodeByName(cur->children, name, ns);
1959                 if(match)
1960                         return match;
1961                 cur = cur->next;
1962         }
1963         return NULL;
1964 }
1965
1966 char *get_sphere(str *pres_uri)
1967 {
1968         unsigned int hash_code;
1969         char *sphere = NULL;
1970         pres_entry_t *p;
1971         db_key_t query_cols[6];
1972         db_val_t query_vals[6];
1973         db_key_t result_cols[6];
1974         db1_res_t *result = NULL;
1975         db_row_t *row = NULL;
1976         db_val_t *row_vals;
1977         int n_result_cols = 0;
1978         int n_query_cols = 0;
1979         struct sip_uri uri;
1980         str body;
1981         static str query_str;
1982
1983
1984         if(!pres_sphere_enable) {
1985                 return NULL;
1986         }
1987
1988         if(publ_cache_mode == PS_PCACHE_HYBRID) {
1989                 /* search in hash table*/
1990                 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
1991
1992                 lock_get(&pres_htable[hash_code].lock);
1993
1994                 p = search_phtable(pres_uri, EVENT_PRESENCE, hash_code);
1995
1996                 if(p) {
1997                         if(p->sphere) {
1998                                 sphere = (char *)pkg_malloc(strlen(p->sphere) * sizeof(char));
1999                                 if(sphere == NULL) {
2000                                         lock_release(&pres_htable[hash_code].lock);
2001                                         ERR_MEM(PKG_MEM_STR);
2002                                 }
2003                                 strcpy(sphere, p->sphere);
2004                         }
2005                         lock_release(&pres_htable[hash_code].lock);
2006                         return sphere;
2007                 }
2008                 lock_release(&pres_htable[hash_code].lock);
2009         }
2010
2011         if(parse_uri(pres_uri->s, pres_uri->len, &uri) < 0) {
2012                 LM_ERR("failed to parse presentity uri\n");
2013                 goto error;
2014         }
2015
2016         query_cols[n_query_cols] = &str_domain_col;
2017         query_vals[n_query_cols].type = DB1_STR;
2018         query_vals[n_query_cols].nul = 0;
2019         query_vals[n_query_cols].val.str_val = uri.host;
2020         n_query_cols++;
2021
2022         query_cols[n_query_cols] = &str_username_col;
2023         query_vals[n_query_cols].type = DB1_STR;
2024         query_vals[n_query_cols].nul = 0;
2025         query_vals[n_query_cols].val.str_val = uri.user;
2026         n_query_cols++;
2027
2028         query_cols[n_query_cols] = &str_event_col;
2029         query_vals[n_query_cols].type = DB1_STR;
2030         query_vals[n_query_cols].nul = 0;
2031         query_vals[n_query_cols].val.str_val.s = "presence";
2032         query_vals[n_query_cols].val.str_val.len = 8;
2033         n_query_cols++;
2034
2035         result_cols[n_result_cols++] = &str_body_col;
2036
2037         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
2038                 LM_ERR("in use_table\n");
2039                 return NULL;
2040         }
2041
2042         if(pres_retrieve_order == 1) {
2043                 query_str = pres_retrieve_order_by;
2044         } else {
2045                 query_str = str_received_time_col;
2046         }
2047         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
2048                            n_result_cols, &query_str, &result)
2049                         < 0) {
2050                 LM_ERR("failed to query %.*s table\n", presentity_table.len,
2051                                 presentity_table.s);
2052                 if(result)
2053                         pa_dbf.free_result(pa_db, result);
2054                 return NULL;
2055         }
2056
2057         if(result == NULL)
2058                 return NULL;
2059
2060         if(result->n <= 0) {
2061                 LM_DBG("no published record found in database\n");
2062                 pa_dbf.free_result(pa_db, result);
2063                 return NULL;
2064         }
2065
2066         row = &result->rows[result->n - 1];
2067         row_vals = ROW_VALUES(row);
2068         if(row_vals[0].val.string_val == NULL) {
2069                 LM_ERR("NULL notify body record\n");
2070                 goto error;
2071         }
2072
2073         body.s = (char *)row_vals[0].val.string_val;
2074         body.len = strlen(body.s);
2075         if(body.len == 0) {
2076                 LM_ERR("Empty notify body record\n");
2077                 goto error;
2078         }
2079
2080         sphere = extract_sphere(&body);
2081
2082         pa_dbf.free_result(pa_db, result);
2083
2084         return sphere;
2085
2086 error:
2087         if(result)
2088                 pa_dbf.free_result(pa_db, result);
2089         return NULL;
2090 }
2091
2092 int mark_presentity_for_delete(presentity_t *pres, str *ruid)
2093 {
2094         db_key_t query_cols[4], result_cols[1], update_cols[3];
2095         db_val_t query_vals[4], update_vals[3], *value;
2096         db_row_t *row;
2097         db1_res_t *result = NULL;
2098         int n_query_cols = 0, n_update_cols = 0;
2099         int ret = -1;
2100         str *cur_body = NULL, *new_body = NULL;
2101         db_query_f query_fn = pa_dbf.query_lock ? pa_dbf.query_lock : pa_dbf.query;
2102
2103         if(pres->event->agg_nbody == NULL) {
2104                 /* Nothing clever to do here... just delete */
2105                 if(delete_presentity(pres, NULL) < 0) {
2106                         LM_ERR("deleting presentity\n");
2107                         goto error;
2108                 }
2109                 goto done;
2110         }
2111
2112         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
2113                 LM_ERR("unsuccessful use table sql operation\n");
2114                 goto error;
2115         }
2116
2117         if(!ruid) {
2118                 query_cols[n_query_cols] = &str_username_col;
2119                 query_vals[n_query_cols].type = DB1_STR;
2120                 query_vals[n_query_cols].nul = 0;
2121                 query_vals[n_query_cols].val.str_val = pres->user;
2122                 n_query_cols++;
2123
2124                 query_cols[n_query_cols] = &str_domain_col;
2125                 query_vals[n_query_cols].type = DB1_STR;
2126                 query_vals[n_query_cols].nul = 0;
2127                 query_vals[n_query_cols].val.str_val = pres->domain;
2128                 n_query_cols++;
2129
2130                 query_cols[n_query_cols] = &str_event_col;
2131                 query_vals[n_query_cols].type = DB1_STR;
2132                 query_vals[n_query_cols].nul = 0;
2133                 query_vals[n_query_cols].val.str_val = pres->event->name;
2134                 n_query_cols++;
2135
2136                 query_cols[n_query_cols] = &str_etag_col;
2137                 query_vals[n_query_cols].type = DB1_STR;
2138                 query_vals[n_query_cols].nul = 0;
2139                 query_vals[n_query_cols].val.str_val = pres->etag;
2140                 n_query_cols++;
2141         } else {
2142                 query_cols[n_query_cols] = &str_ruid_col;
2143                 query_vals[n_query_cols].type = DB1_STR;
2144                 query_vals[n_query_cols].nul = 0;
2145                 query_vals[n_query_cols].val.str_val = *ruid;
2146                 n_query_cols++;
2147         }
2148
2149         result_cols[0] = &str_body_col;
2150
2151         if(query_fn(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols, 1,
2152                            0, &result)
2153                         < 0) {
2154                 LM_ERR("query failed\n");
2155                 goto error;
2156         }
2157
2158         if(result == NULL) {
2159                 LM_ERR("bad result\n");
2160                 goto error;
2161         }
2162
2163         if(RES_ROW_N(result) <= 0) {
2164                 /* Can happen when the timer and notifier processes clash */
2165                 LM_INFO("Found 0 presentities - expected 1\n");
2166                 goto done;
2167         }
2168
2169         if(RES_ROW_N(result) > 1) {
2170                 /* More that one is prevented by DB constraint  - but handle
2171                  * it anyway */
2172                 LM_ERR("Found %d presentities - expected 1\n", RES_ROW_N(result));
2173
2174                 if(delete_presentity(pres, ruid) < 0) {
2175                         LM_ERR("deleting presentity\n");
2176                         goto error;
2177                 }
2178
2179                 /* Want the calling function to continue properly so do not
2180                  * return an error */
2181                 goto done;
2182         }
2183
2184         row = RES_ROWS(result);
2185         value = ROW_VALUES(row);
2186
2187         if((cur_body = (str *)pkg_malloc(sizeof(str))) == NULL) {
2188                 LM_ERR("allocating pkg memory\n");
2189                 goto error;
2190         }
2191         cur_body->s = (char *)value->val.string_val;
2192         cur_body->len = strlen(cur_body->s);
2193         if((new_body = pres->event->agg_nbody(
2194                                 &pres->user, &pres->domain, &cur_body, 1, 0))
2195                         == NULL) {
2196                 LM_ERR("preparing body\n");
2197                 goto error;
2198         }
2199
2200         update_cols[n_update_cols] = &str_etag_col;
2201         update_vals[n_update_cols].type = DB1_STR;
2202         update_vals[n_update_cols].nul = 0;
2203         update_vals[n_update_cols].val.str_val = str_offline_etag_val;
2204         n_update_cols++;
2205
2206         update_cols[n_update_cols] = &str_expires_col;
2207         update_vals[n_update_cols].type = DB1_INT;
2208         update_vals[n_update_cols].nul = 0;
2209         update_vals[n_update_cols].val.int_val = (int)time(NULL);
2210         n_update_cols++;
2211
2212         update_cols[n_update_cols] = &str_body_col;
2213         update_vals[n_update_cols].type = DB1_STR;
2214         update_vals[n_update_cols].nul = 0;
2215         update_vals[n_update_cols].val.str_val.s = new_body->s;
2216         update_vals[n_update_cols].val.str_val.len = new_body->len;
2217         n_update_cols++;
2218
2219         if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols, update_vals,
2220                            n_query_cols, n_update_cols)
2221                         < 0) {
2222                 LM_ERR("unsuccessful sql update operation");
2223                 goto error;
2224         }
2225
2226         if(pa_dbf.affected_rows)
2227                 ret = pa_dbf.affected_rows(pa_db);
2228         else
2229         done:
2230                 ret = 0;
2231
2232 error:
2233         free_notify_body(new_body, pres->event);
2234         if(cur_body)
2235                 pkg_free(cur_body);
2236         if(result)
2237                 pa_dbf.free_result(pa_db, result);
2238
2239         return ret;
2240 }
2241
2242 /**
2243  *
2244  */
2245 int ps_db_delete_presentity(presentity_t *pres, str *ruid)
2246 {
2247         db_key_t query_cols[4];
2248         db_val_t query_vals[4];
2249         int n_query_cols = 0;
2250
2251         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
2252                 LM_ERR("unsuccessful use table sql operation\n");
2253                 goto error;
2254         }
2255
2256         if(!ruid) {
2257                 query_cols[n_query_cols] = &str_username_col;
2258                 query_vals[n_query_cols].type = DB1_STR;
2259                 query_vals[n_query_cols].nul = 0;
2260                 query_vals[n_query_cols].val.str_val = pres->user;
2261                 n_query_cols++;
2262
2263                 query_cols[n_query_cols] = &str_domain_col;
2264                 query_vals[n_query_cols].type = DB1_STR;
2265                 query_vals[n_query_cols].nul = 0;
2266                 query_vals[n_query_cols].val.str_val = pres->domain;
2267                 n_query_cols++;
2268
2269                 query_cols[n_query_cols] = &str_event_col;
2270                 query_vals[n_query_cols].type = DB1_STR;
2271                 query_vals[n_query_cols].nul = 0;
2272                 query_vals[n_query_cols].val.str_val = pres->event->name;
2273                 n_query_cols++;
2274
2275                 query_cols[n_query_cols] = &str_etag_col;
2276                 query_vals[n_query_cols].type = DB1_STR;
2277                 query_vals[n_query_cols].nul = 0;
2278                 query_vals[n_query_cols].val.str_val = pres->etag;
2279                 n_query_cols++;
2280         } else {
2281                 query_cols[n_query_cols] = &str_ruid_col;
2282                 query_vals[n_query_cols].type = DB1_STR;
2283                 query_vals[n_query_cols].nul = 0;
2284                 query_vals[n_query_cols].val.str_val = *ruid;
2285                 n_query_cols++;
2286         }
2287
2288         if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0) {
2289                 LM_ERR("unsuccessful sql delete operation");
2290                 goto error;
2291         }
2292
2293         if(pa_dbf.affected_rows)
2294                 return pa_dbf.affected_rows(pa_db);
2295         else
2296                 return 0;
2297
2298 error:
2299         return -1;
2300 }
2301
2302 /**
2303  *
2304  */
2305 int ps_cache_delete_presentity(presentity_t *pres, str *ruid)
2306 {
2307         ps_presentity_t ptc;
2308
2309         memset(&ptc, 0, sizeof(ps_presentity_t));
2310
2311         ptc.user = pres->user;
2312         ptc.domain = pres->domain;
2313         ptc.event = pres->event->name;
2314         ptc.etag = pres->etag;
2315
2316         if(ps_ptable_remove(&ptc) < 0) {
2317                 return -1;
2318         }
2319
2320         return 0;
2321 }
2322
2323 /**
2324  *
2325  */
2326 int delete_presentity(presentity_t *pres, str *ruid)
2327 {
2328         if(publ_cache_mode == PS_PCACHE_RECORD) {
2329                 return ps_cache_delete_presentity(pres, ruid);
2330         } else {
2331                 return ps_db_delete_presentity(pres, ruid);
2332         }
2333 }
2334
2335 int delete_offline_presentities(str *pres_uri, pres_ev_t *event)
2336 {
2337         db_key_t query_cols[4];
2338         db_val_t query_vals[4];
2339         int n_query_cols = 0;
2340         struct sip_uri uri;
2341
2342         if(parse_uri(pres_uri->s, pres_uri->len, &uri) < 0) {
2343                 LM_ERR("failed to parse presentity uri\n");
2344                 goto error;
2345         }
2346
2347         query_cols[n_query_cols] = &str_username_col;
2348         query_vals[n_query_cols].type = DB1_STR;
2349         query_vals[n_query_cols].nul = 0;
2350         query_vals[n_query_cols].val.str_val = uri.user;
2351         n_query_cols++;
2352
2353         query_cols[n_query_cols] = &str_domain_col;
2354         query_vals[n_query_cols].type = DB1_STR;
2355         query_vals[n_query_cols].nul = 0;
2356         query_vals[n_query_cols].val.str_val = uri.host;
2357         n_query_cols++;
2358
2359         query_cols[n_query_cols] = &str_event_col;
2360         query_vals[n_query_cols].type = DB1_STR;
2361         query_vals[n_query_cols].nul = 0;
2362         query_vals[n_query_cols].val.str_val = event->name;
2363         n_query_cols++;
2364
2365         query_cols[n_query_cols] = &str_etag_col;
2366         query_vals[n_query_cols].type = DB1_STR;
2367         query_vals[n_query_cols].nul = 0;
2368         query_vals[n_query_cols].val.str_val = str_offline_etag_val;
2369         n_query_cols++;
2370
2371         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
2372                 LM_ERR("unsuccessful use table sql operation\n");
2373                 goto error;
2374         }
2375
2376         if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0) {
2377                 LM_ERR("unsuccessful sql delete operation");
2378                 goto error;
2379         }
2380
2381         if(pa_dbf.affected_rows)
2382                 return pa_dbf.affected_rows(pa_db);
2383         else
2384                 return 0;
2385
2386 error:
2387         return -1;
2388 }
2389
2390 // used for API updates to the presentity table
2391 int _api_update_presentity(str *event, str *realm, str *user, str *etag,
2392                 str *sender, str *body, int expires, int new_t, int replace)
2393 {
2394         int ret = -1;
2395         presentity_t *pres = NULL;
2396         pres_ev_t *ev = NULL;
2397         char *sphere = NULL;
2398
2399         ev = contains_event(event, NULL);
2400         if(ev == NULL) {
2401                 LM_ERR("wrong event parameter\n");
2402                 return -1;
2403         }
2404
2405         pres = new_presentity(realm, user, expires, ev, etag, sender);
2406
2407         if(pres_sphere_enable) {
2408                 sphere = extract_sphere(body);
2409         }
2410         if(pres) {
2411                 ret = update_presentity(
2412                                 NULL, pres, body, new_t, NULL, sphere, NULL, NULL, replace);
2413                 pkg_free(pres);
2414         }
2415
2416         if(sphere)
2417                 pkg_free(sphere);
2418
2419         return ret;
2420 }