modules_k/presence/presentity.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice Sistem S.R.L.
00003  *
00004  * This file is part of Kamailio, a free SIP server.
00005  *
00006  * Kamailio is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * Kamailio is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License 
00017  * along with this program; if not, write to the Free Software 
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  * History:
00021  * --------
00022  *  2006-08-15  initial version (Anca Vamanu)
00023  */
00024 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <time.h>
00036 
00037 #include "../../lib/srdb1/db.h"
00038 #include "../../hashes.h"
00039 #include "../../dprint.h"
00040 #include "../../mem/shm_mem.h"
00041 #include "../../str.h"
00042 #include "../alias_db/alias_db.h"
00043 #include "../../data_lump_rpl.h"
00044 #include "presentity.h"
00045 #include "presence.h" 
00046 #include "notify.h"
00047 #include "publish.h"
00048 #include "hash.h"
00049 #include "utils_func.h"
00050 
00051 
00052 xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
00053                                                                                                         const char *ns);
00054 static str pu_200_rpl  = str_init("OK");
00055 static str pu_412_rpl  = str_init("Conditional request failed");
00056 
00057 static str str_offline_etag_val = str_init("*#-OFFLINE-#*");
00058 
00059 #define ETAG_LEN  128
00060 
00061 char* generate_ETag(int publ_count)
00062 {
00063         char* etag= NULL;
00064         int size = 0;
00065 
00066         etag = (char*)pkg_malloc(ETAG_LEN*sizeof(char));
00067         if(etag ==NULL)
00068         {
00069                 ERR_MEM(PKG_MEM_STR);
00070         }
00071         memset(etag, 0, ETAG_LEN*sizeof(char));
00072         size = snprintf (etag, ETAG_LEN, "%c.%d.%d.%d.%d",prefix, startup_time, pid, counter, publ_count);
00073         if( size <0 )
00074         {
00075                 LM_ERR("unsuccessfull snprintf\n ");
00076                 pkg_free(etag);
00077                 return NULL;
00078         }
00079         if(size >= ETAG_LEN)
00080         {
00081                 LM_ERR("buffer size overflown\n");
00082                 pkg_free(etag);
00083                 return NULL;
00084         }
00085 
00086         etag[size] = '\0';
00087         LM_DBG("etag= %s / %d\n ",etag, size);
00088         return etag;
00089 
00090 error:
00091         return NULL;
00092 
00093 }
00094 
00095 int publ_send200ok(struct sip_msg *msg, int lexpire, str etag)
00096 {
00097         char buf[128];
00098         int buf_len= 128, size;
00099         str hdr_append= {0, 0}, hdr_append2= {0, 0} ;
00100 
00101         if (msg == NULL)
00102                 return 0;
00103 
00104         LM_DBG("send 200OK reply\n");   
00105         LM_DBG("etag= %s - len= %d\n", etag.s, etag.len);
00106         
00107         hdr_append.s = buf;
00108         hdr_append.s[0]='\0';
00109         hdr_append.len = snprintf(hdr_append.s, buf_len, "Expires: %d\r\n",
00110                         ((lexpire==0)?0:(lexpire-expires_offset)));
00111         if(hdr_append.len < 0)
00112         {
00113                 LM_ERR("unsuccessful snprintf\n");
00114                 goto error;
00115         }
00116         if(hdr_append.len >= buf_len)
00117         {
00118                 LM_ERR("buffer size overflown\n");
00119                 goto error;
00120         }
00121         hdr_append.s[hdr_append.len]= '\0';
00122                 
00123         if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 )
00124         {
00125                 LM_ERR("unable to add lump_rl\n");
00126                 goto error;
00127         }
00128 
00129         size= sizeof(char)*(20+etag.len) ;
00130         hdr_append2.s = (char *)pkg_malloc(size);
00131         if(hdr_append2.s == NULL)
00132         {
00133                 ERR_MEM(PKG_MEM_STR);
00134         }
00135         hdr_append2.s[0]='\0';
00136         hdr_append2.len = snprintf(hdr_append2.s, size, "SIP-ETag: %s\r\n", etag.s);
00137         if(hdr_append2.len < 0)
00138         {
00139                 LM_ERR("unsuccessful snprintf\n ");
00140                 goto error;
00141         }
00142         if(hdr_append2.len >= size)
00143         {
00144                 LM_ERR("buffer size overflown\n");
00145                 goto error;
00146         }
00147 
00148         hdr_append2.s[hdr_append2.len]= '\0';
00149         if (add_lump_rpl(msg, hdr_append2.s, hdr_append2.len, LUMP_RPL_HDR)==0 )
00150         {
00151                 LM_ERR("unable to add lump_rl\n");
00152                 goto error;
00153         }
00154 
00155         if(slb.freply(msg, 200, &pu_200_rpl) < 0)
00156         {
00157                 LM_ERR("sending reply\n");
00158                 goto error;
00159         }
00160 
00161         pkg_free(hdr_append2.s);
00162         return 0;
00163 
00164 error:
00165 
00166         if(hdr_append2.s)
00167                 pkg_free(hdr_append2.s);
00168 
00169         return -1;
00170 }       
00171 presentity_t* new_presentity( str* domain,str* user,int expires, 
00172                 pres_ev_t* event, str* etag, str* sender)
00173 {
00174         presentity_t *presentity= NULL;
00175         int size, init_len;
00176         
00177         /* allocating memory for presentity */
00178         size = sizeof(presentity_t)+ domain->len+ user->len+ etag->len +1;
00179         if(sender)
00180                 size+= sizeof(str)+ sender->len* sizeof(char);
00181         
00182         init_len= size;
00183 
00184         presentity = (presentity_t*)pkg_malloc(size);
00185         if(presentity == NULL)
00186         {
00187                 ERR_MEM(PKG_MEM_STR);
00188         }
00189         memset(presentity, 0, size);
00190         size= sizeof(presentity_t);
00191 
00192         presentity->domain.s = (char*)presentity+ size;
00193         strncpy(presentity->domain.s, domain->s, domain->len);
00194         presentity->domain.len = domain->len;
00195         size+= domain->len;     
00196         
00197         presentity->user.s = (char*)presentity+size;
00198         strncpy(presentity->user.s, user->s, user->len);
00199         presentity->user.len = user->len;
00200         size+= user->len;
00201 
00202         presentity->etag.s = (char*)presentity+ size;
00203         memcpy(presentity->etag.s, etag->s, etag->len);
00204         presentity->etag.s[etag->len]= '\0';
00205         presentity->etag.len = etag->len;
00206 
00207         size+= etag->len+1;
00208         
00209         if(sender)
00210         {
00211                 presentity->sender= (str*)((char*)presentity+ size);
00212                 size+= sizeof(str);
00213                 presentity->sender->s= (char*)presentity + size;
00214                 memcpy(presentity->sender->s, sender->s, sender->len);
00215                 presentity->sender->len= sender->len;
00216                 size+= sender->len;
00217         }
00218 
00219         if(size> init_len)
00220         {
00221                 LM_ERR("buffer size overflow init_len= %d, size= %d\n", init_len, size);
00222                 goto error;
00223         }
00224         presentity->event= event;
00225         presentity->expires = expires;
00226         presentity->received_time= (int)time(NULL);
00227         return presentity;
00228     
00229 error:
00230         if(presentity)
00231                 pkg_free(presentity);
00232         return NULL;
00233 }
00234 
00235 xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
00236 {
00237         xmlNodePtr cur = node->children;
00238         while (cur) {
00239                 if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0)
00240                         return cur;
00241                 cur = cur->next;
00242         }
00243         return NULL;
00244 }
00245 
00246 int check_if_dialog(str body, int *is_dialog)
00247 {
00248         xmlDocPtr doc;
00249         xmlNodePtr node;
00250 
00251         doc = xmlParseMemory(body.s, body.len);
00252         if(doc== NULL)
00253         {
00254                 LM_ERR("failed to parse xml document\n");
00255                 return -1;
00256         }
00257 
00258         node = doc->children;
00259         node = xmlNodeGetChildByName(node, "dialog");
00260 
00261         if(node == NULL)
00262                 *is_dialog = 0;
00263         else
00264                 *is_dialog = 1;
00265 
00266         xmlFreeDoc(doc);
00267         return 0;
00268 }
00269 
00270 
00271 int update_presentity(struct sip_msg* msg, presentity_t* presentity, str* body,
00272                 int new_t, int* sent_reply, char* sphere)
00273 {
00274         db_key_t query_cols[12], update_keys[8], result_cols[5];
00275         db_op_t  query_ops[12];
00276         db_val_t query_vals[12], update_vals[8];
00277         db1_res_t *result= NULL;
00278         int n_query_cols = 0;
00279         int n_update_cols = 0;
00280         char* dot= NULL;
00281         str etag= {0, 0};
00282         str cur_etag= {0, 0};
00283         str* rules_doc= NULL;
00284         str pres_uri= {0, 0};
00285         int rez_body_col, rez_sender_col, n_result_cols= 0;
00286         db_row_t *row = NULL ;
00287         db_val_t *row_vals = NULL;
00288         str old_body, sender;
00289         int is_dialog= 0, bla_update_publish= 1;
00290         int affected_rows = 0;
00291         int ret = -1;
00292         int db_record_exists = 0;
00293         int num_watchers = 0;
00294 
00295         if (sent_reply) *sent_reply= 0;
00296         if(pres_notifier_processes == 0 && presentity->event->req_auth)
00297         {
00298                 /* get rules_document */
00299                 if(presentity->event->get_rules_doc(&presentity->user,
00300                                         &presentity->domain, &rules_doc))
00301                 {
00302                         LM_ERR("getting rules doc\n");
00303                         goto error;
00304                 }
00305         }
00306         
00307         if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri)< 0)
00308         {
00309                 LM_ERR("constructing uri from user and domain\n");
00310                 goto error;
00311         }
00312 
00313 
00314         query_cols[n_query_cols] = &str_domain_col;
00315         query_ops[n_query_cols] = OP_EQ;
00316         query_vals[n_query_cols].type = DB1_STR;
00317         query_vals[n_query_cols].nul = 0;
00318         query_vals[n_query_cols].val.str_val = presentity->domain;
00319         n_query_cols++;
00320         
00321         query_cols[n_query_cols] = &str_username_col;
00322         query_ops[n_query_cols] = OP_EQ;
00323         query_vals[n_query_cols].type = DB1_STR;
00324         query_vals[n_query_cols].nul = 0;
00325         query_vals[n_query_cols].val.str_val = presentity->user;
00326         n_query_cols++;
00327 
00328         query_cols[n_query_cols] = &str_event_col;
00329         query_ops[n_query_cols] = OP_EQ;
00330         query_vals[n_query_cols].type = DB1_STR;
00331         query_vals[n_query_cols].nul = 0;
00332         query_vals[n_query_cols].val.str_val = presentity->event->name;
00333         n_query_cols++;
00334 
00335         query_cols[n_query_cols] = &str_etag_col;
00336         query_ops[n_query_cols] = OP_EQ;
00337         query_vals[n_query_cols].type = DB1_STR;
00338         query_vals[n_query_cols].nul = 0;
00339         query_vals[n_query_cols].val.str_val = presentity->etag;
00340         n_query_cols++;
00341 
00342         result_cols[rez_body_col= n_result_cols++] = &str_body_col;
00343         result_cols[rez_sender_col= n_result_cols++] = &str_sender_col;
00344 
00345         if(new_t) 
00346         {
00347                 /* insert new record in hash_table */
00348 
00349                 if ( publ_cache_enabled &&
00350                         insert_phtable(&pres_uri, presentity->event->evp->type, sphere)< 0)
00351                 {
00352                         LM_ERR("inserting record in hash table\n");
00353                         goto error;
00354                 }
00355                 
00356                 /* insert new record into database */   
00357                 query_cols[n_query_cols] = &str_sender_col;
00358                 query_vals[n_query_cols].type = DB1_STR;
00359                 query_vals[n_query_cols].nul = 0;
00360                 if(presentity->sender)
00361                 {
00362                         query_vals[n_query_cols].val.str_val.s = presentity->sender->s;
00363                         query_vals[n_query_cols].val.str_val.len = presentity->sender->len;
00364                 } else {
00365                         query_vals[n_query_cols].val.str_val.s = "";
00366                         query_vals[n_query_cols].val.str_val.len = 0;
00367                 }
00368                 n_query_cols++;
00369 
00370                 query_cols[n_query_cols] = &str_body_col;
00371                 query_vals[n_query_cols].type = DB1_BLOB;
00372                 query_vals[n_query_cols].nul = 0;
00373                 query_vals[n_query_cols].val.str_val = *body;
00374                 n_query_cols++;
00375                 
00376                 query_cols[n_query_cols] = &str_received_time_col;
00377                 query_vals[n_query_cols].type = DB1_INT;
00378                 query_vals[n_query_cols].nul = 0;
00379                 query_vals[n_query_cols].val.int_val = presentity->received_time;
00380                 n_query_cols++;
00381                 
00382                 if (presentity->expires != -1)
00383                 {
00384                         /* A real PUBLISH */
00385                         query_cols[n_query_cols] = &str_expires_col;
00386                         query_vals[n_query_cols].type = DB1_INT;
00387                         query_vals[n_query_cols].nul = 0;
00388                         query_vals[n_query_cols].val.int_val = presentity->expires+
00389                                                                 (int)time(NULL);
00390                         n_query_cols++;
00391         
00392                         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
00393                         {
00394                                 LM_ERR("unsuccessful use_table\n");
00395                                 goto error;
00396                         }
00397 
00398                         LM_DBG("inserting %d cols into table\n",n_query_cols);
00399                                 
00400                         if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) 
00401                         {
00402                                 LM_ERR("inserting new record in database\n");
00403                                 goto error;
00404                         }
00405                 }
00406                 else
00407                 {
00408                         /* A hard-state PUBLISH */
00409                         query_cols[n_query_cols] = &str_expires_col;
00410                         query_vals[n_query_cols].type = DB1_INT;
00411                         query_vals[n_query_cols].nul = 0;
00412                         query_vals[n_query_cols].val.int_val = -1;
00413                         n_query_cols++;
00414         
00415                         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
00416                         {
00417                                 LM_ERR("unsuccessful use_table\n");
00418                                 goto error;
00419                         }
00420 
00421                         if (pa_dbf.replace == NULL)
00422                         {
00423                                 LM_ERR("replace is required for pidf-manipulation support\n");
00424                                 goto error;
00425                         }
00426                         if (pa_dbf.replace(pa_db, query_cols, query_vals, n_query_cols, 4, 0) < 0) 
00427                         {
00428                                 LM_ERR("replacing record in database\n");
00429                                 goto error;
00430                         }
00431                 }
00432 
00433                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
00434                 {
00435                         LM_ERR("sending 200OK\n");
00436                         goto error;
00437                 }
00438                 if (sent_reply) *sent_reply= 1;
00439                 goto send_notify;
00440         }
00441         else
00442         {       
00443 
00444                 if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
00445                 {
00446                         LM_ERR("unsuccessful sql use table\n");
00447                         goto error;
00448                 }
00449 
00450                 if(EVENT_DIALOG_SLA(presentity->event->evp))
00451                 {
00452 
00453                         if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
00454                          result_cols, n_query_cols, n_result_cols, 0, &result) < 0) 
00455                         {
00456                                 LM_ERR("unsuccessful sql query\n");
00457                                 goto error;
00458                         }
00459                         if(result== NULL)
00460                                 goto error;
00461 
00462                         if (!(result->n > 0))
00463                                 goto send_412;
00464                         
00465                         db_record_exists= 1;
00466                         /* analize if previous body has a dialog */
00467                         row = &result->rows[0];
00468                         row_vals = ROW_VALUES(row);
00469 
00470                         old_body.s = (char*)row_vals[rez_body_col].val.string_val;
00471                         old_body.len = strlen(old_body.s);
00472                         if(check_if_dialog(*body, &is_dialog)< 0)
00473                         {
00474                                 LM_ERR("failed to check if dialog stored\n");
00475                                 goto error;
00476                         }
00477 
00478                         if(is_dialog== 1)  /* if the new body has a dialog - overwrite */
00479                                 goto after_dialog_check;
00480 
00481                         if(check_if_dialog(old_body, &is_dialog)< 0)
00482                         {
00483                                 LM_ERR("failed to check if dialog stored\n");
00484                                 goto error;
00485                         }
00486 
00487                         if(is_dialog==0 ) /* if the old body has no dialog - overwrite */
00488                                 goto after_dialog_check;
00489 
00490                         sender.s = (char*)row_vals[rez_sender_col].val.string_val;
00491                         sender.len= strlen(sender.s);
00492 
00493                         LM_DBG("old_sender = %.*s\n", sender.len, sender.s );
00494                         if(presentity->sender)
00495                         {
00496                                 if(!(presentity->sender->len == sender.len && 
00497                                 strncmp(presentity->sender->s, sender.s, sender.len)== 0))
00498                                          bla_update_publish= 0;
00499                         }
00500 after_dialog_check:
00501                         pa_dbf.free_result(pa_db, result);
00502                         result = NULL;
00503                         
00504                 }
00505 
00506                 if(presentity->expires <= 0) 
00507                 {
00508 
00509                         if (!db_record_exists)
00510                         {
00511                                 if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
00512                                         result_cols, n_query_cols, n_result_cols, 0, &result) < 0) 
00513                                 {
00514                                         LM_ERR("unsuccessful sql query\n");
00515                                         goto error;
00516                                 }
00517                                 if(result== NULL)
00518                                         goto error;
00519 
00520                                 if (!(result->n > 0))
00521                                         goto send_412;
00522 
00523                                 db_record_exists = 1;
00524 
00525                                 pa_dbf.free_result(pa_db, result);
00526                                 result = NULL;
00527                         }
00528 
00529                         if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
00530                         {
00531                                 LM_ERR("sending 200OK reply\n");
00532                                 goto error;
00533                         }
00534                         if (sent_reply) *sent_reply= 1;
00535 
00536                         if (pres_notifier_processes > 0)
00537                         {
00538                                 if ((num_watchers = publ_notify_notifier(pres_uri, presentity->event)) < 0)
00539                                 {
00540                                         LM_ERR("updating watcher records\n");
00541                                         goto error;
00542                                 }
00543 
00544                                 if (num_watchers > 0)
00545                                 {
00546                                         if (mark_presentity_for_delete(presentity) < 0)
00547                                         {
00548                                                 LM_ERR("Marking presentities\n");
00549                                                 goto error;
00550                                         }
00551                                 }
00552                         }
00553                         else
00554                         {
00555                                 if( publ_notify( presentity, pres_uri, body, &presentity->etag, rules_doc)< 0 )
00556                                 {
00557                                         LM_ERR("while sending notify\n");
00558                                         goto error;
00559                                 }
00560                         }
00561 
00562                         if (pres_notifier_processes == 0 || num_watchers == 0)
00563                         {
00564                                 if (delete_presentity(presentity) < 0)
00565                                 {
00566                                         LM_ERR("Deleting presentity\n");
00567                                         goto error;
00568                                 }
00569 
00570                                 LM_DBG("deleted from db %.*s\n", presentity->user.len, presentity->user.s);
00571                         }
00572 
00573                         /* delete from hash table */
00574                         if( publ_cache_enabled &&
00575                                 delete_phtable(&pres_uri, presentity->event->evp->type)< 0)
00576                         {
00577                                 LM_ERR("deleting record from hash table\n");
00578                                 goto error;
00579                         }
00580                         goto done;
00581                 }
00582 
00583                 n_update_cols= 0;
00584                 /* if event dialog and is_dialog -> if sender not the same as
00585                  * old sender do not overwrite */
00586                 if( EVENT_DIALOG_SLA(presentity->event->evp) &&  bla_update_publish==0)
00587                 {
00588                         LM_DBG("drop Publish for BLA from a different sender that"
00589                                         " wants to overwrite an existing dialog\n");
00590                         LM_DBG("sender = %.*s\n",  presentity->sender->len, presentity->sender->s );
00591                                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
00592                                 {
00593                                         LM_ERR("sending 200OK reply\n");
00594                                         goto error;
00595                                 }
00596                         if (sent_reply) *sent_reply= 1;
00597                         goto done;
00598                 }
00599 
00600                 if(presentity->event->etag_not_new== 0)
00601                 {       
00602                         /* generate another etag */
00603                         unsigned int publ_nr;
00604                         str str_publ_nr= {0, 0};
00605 
00606                         dot= presentity->etag.s+ presentity->etag.len;
00607                         while(*dot!= '.' && str_publ_nr.len< presentity->etag.len)
00608                         {
00609                                 str_publ_nr.len++;
00610                                 dot--;
00611                         }
00612                         if(str_publ_nr.len== presentity->etag.len)
00613                         {
00614                                 LM_ERR("wrong etag\n");
00615                                 goto error;
00616                         }       
00617                         str_publ_nr.s= dot+1;
00618                         str_publ_nr.len--;
00619 
00620                         if( str2int(&str_publ_nr, &publ_nr)< 0)
00621                         {
00622                                 LM_ERR("converting string to int\n");
00623                                 goto error;
00624                         }
00625                         etag.s = generate_ETag(publ_nr+1);
00626                         if(etag.s == NULL)
00627                         {
00628                                 LM_ERR("while generating etag\n");
00629                                 goto error;
00630                         }
00631                         etag.len=(strlen(etag.s));
00632                         
00633                         cur_etag= etag;
00634 
00635                         update_keys[n_update_cols] = &str_etag_col;
00636                         update_vals[n_update_cols].type = DB1_STR;
00637                         update_vals[n_update_cols].nul = 0;
00638                         update_vals[n_update_cols].val.str_val = etag;
00639                         n_update_cols++;
00640 
00641                 }
00642                 else
00643                         cur_etag= presentity->etag;
00644                         
00645                 update_keys[n_update_cols] = &str_expires_col;
00646                 update_vals[n_update_cols].type = DB1_INT;
00647                 update_vals[n_update_cols].nul = 0;
00648                 update_vals[n_update_cols].val.int_val= presentity->expires +
00649                         (int)time(NULL);
00650                 n_update_cols++;
00651 
00652                 update_keys[n_update_cols] = &str_received_time_col;
00653                 update_vals[n_update_cols].type = DB1_INT;
00654                 update_vals[n_update_cols].nul = 0;
00655                 update_vals[n_update_cols].val.int_val= presentity->received_time;
00656                 n_update_cols++;
00657 
00658                 if(body && body->s)
00659                 {
00660                         update_keys[n_update_cols] = &str_body_col;
00661                         update_vals[n_update_cols].type = DB1_BLOB;
00662                         update_vals[n_update_cols].nul = 0;
00663                         update_vals[n_update_cols].val.str_val = *body;
00664                         n_update_cols++;
00665 
00666                         /* updated stored sphere */
00667                         if(sphere_enable && 
00668                                         presentity->event->evp->type== EVENT_PRESENCE)
00669                         {
00670                                 if( publ_cache_enabled &&
00671                                                 update_phtable(presentity, pres_uri, *body)< 0)
00672                                 {
00673                                         LM_ERR("failed to update sphere for presentity\n");
00674                                         goto error;
00675                                 }
00676                         }
00677                 }
00678                 
00679                 
00680                 if( presentity->sender)
00681                 {
00682                         update_keys[n_update_cols] = &str_sender_col;
00683                         update_vals[n_update_cols].type = DB1_STR;
00684                         update_vals[n_update_cols].nul = 0;
00685                         update_vals[n_update_cols].val.str_val = *presentity->sender;
00686                         n_update_cols++;
00687                 }
00688 
00689                 /* if there is no support for affected_rows and no previous query has been done, do query */
00690                 if (!pa_dbf.affected_rows && !db_record_exists)
00691                 {
00692                         if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
00693                          result_cols, n_query_cols, n_result_cols, 0, &result) < 0) 
00694                         {
00695                                 LM_ERR("unsuccessful sql query\n");
00696                                 goto error;
00697                         }
00698                         if(result== NULL)
00699                                 goto error;
00700                         
00701                         if (!(result->n > 0))
00702                                 goto send_412;
00703 
00704                         db_record_exists = 1;
00705                         pa_dbf.free_result(pa_db, result);
00706                         result = NULL;
00707                 }
00708 
00709                 if( pa_dbf.update( pa_db,query_cols, query_ops, query_vals,
00710                                 update_keys, update_vals, n_query_cols, n_update_cols )<0) 
00711                 {
00712                         LM_ERR("updating published info in database\n");
00713                         goto error;
00714                 }
00715 
00716                 if (pa_dbf.affected_rows && !db_record_exists)
00717                 {
00718                         if ((affected_rows = pa_dbf.affected_rows ( pa_db ))<0)
00719                                 {
00720                                         LM_ERR("unsuccessful sql affected rows operation");
00721                                         goto error;
00722                                 }
00723 
00724                                 LM_DBG ("affected rows after update: %d\n", affected_rows );
00725                 }
00726 
00727 
00728                 /*if either affected_rows (if exists) or select query show that there is no line in database*/
00729                 if ((pa_dbf.affected_rows && !affected_rows) || (!pa_dbf.affected_rows && !db_record_exists))
00730                         goto send_412;
00731 
00732                 /* send 200OK */
00733                 if (publ_send200ok(msg, presentity->expires, cur_etag)< 0)
00734                 {
00735                         LM_ERR("sending 200OK reply\n");
00736                         goto error;
00737                 }
00738                 if (sent_reply) *sent_reply= 1;
00739 
00740                 if(etag.s)
00741                         pkg_free(etag.s);
00742                 etag.s= NULL;
00743 
00744                 if(!body)
00745                         goto done;
00746         }
00747 
00748 send_notify:
00749 
00750         /* send notify with presence information */
00751         if (pres_notifier_processes > 0)
00752         {
00753                 if (publ_notify_notifier(pres_uri, presentity->event) < 0)
00754                 {
00755                         LM_ERR("updating watcher records\n");
00756                         goto error;
00757                 }
00758         }
00759         else
00760         {
00761                 if( publ_notify( presentity, pres_uri, body, NULL, rules_doc)< 0 )
00762                 {
00763                         LM_ERR("while sending notify\n");
00764                         goto error;
00765                 }
00766         }
00767 
00768 done:
00769         if(rules_doc)
00770         {
00771                 if(rules_doc->s)
00772                         pkg_free(rules_doc->s);
00773                 pkg_free(rules_doc);
00774         }
00775         if(pres_uri.s)
00776                 pkg_free(pres_uri.s);
00777 
00778         return 0;
00779 
00780 send_412:
00781 
00782         LM_ERR("No E_Tag match %*s\n", presentity->etag.len, presentity->etag.s);
00783         if (msg != NULL)
00784         {
00785                 if (slb.freply(msg, 412, &pu_412_rpl) < 0)
00786                 {
00787                         LM_ERR("sending '412 Conditional request failed' reply\n");
00788                         goto error;
00789                 }
00790         }
00791         if (sent_reply) *sent_reply= 1;
00792         ret = 0;
00793 
00794 error:
00795         if(result)
00796                 pa_dbf.free_result(pa_db, result);
00797         if(etag.s)
00798                 pkg_free(etag.s);
00799         if(rules_doc)
00800         {
00801                 if(rules_doc->s)
00802                         pkg_free(rules_doc->s);
00803                 pkg_free(rules_doc);
00804         }
00805         if(pres_uri.s)
00806                 pkg_free(pres_uri.s);
00807 
00808         return ret;
00809 }
00810 
00811 int pres_htable_restore(void)
00812 {
00813         /* query all records from presentity table and insert records 
00814          * in presentity table */
00815         db_key_t result_cols[6];
00816         db1_res_t *result= NULL;
00817         db_row_t *row= NULL ;
00818         db_val_t *row_vals;
00819         int  i;
00820         str user, domain, ev_str, uri, body;
00821         int n_result_cols= 0;
00822         int user_col, domain_col, event_col, expires_col, body_col = 0;
00823         int event;
00824         event_t ev;
00825         char* sphere= NULL;
00826 
00827         result_cols[user_col= n_result_cols++]= &str_username_col;
00828         result_cols[domain_col= n_result_cols++]= &str_domain_col;
00829         result_cols[event_col= n_result_cols++]= &str_event_col;
00830         result_cols[expires_col= n_result_cols++]= &str_expires_col;
00831         if(sphere_enable)
00832                 result_cols[body_col= n_result_cols++]= &str_body_col;
00833 
00834         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
00835         {
00836                 LM_ERR("unsuccessful use table sql operation\n");
00837                 goto error;
00838         }
00839 
00840         static str query_str = str_init("username");
00841         if (db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, 0, 0, 0, result_cols,
00842                                 0, n_result_cols, &query_str, &result) < 0)
00843         {
00844                 LM_ERR("querying presentity\n");
00845                 goto error;
00846         }
00847         if(result== NULL)
00848                 goto error;
00849 
00850         if(result->n<= 0)
00851         {
00852                 pa_dbf.free_result(pa_db, result);
00853                 return 0;
00854         }
00855 
00856         do {
00857                 for(i= 0; i< result->n; i++)
00858                 {
00859                         row = &result->rows[i];
00860                         row_vals = ROW_VALUES(row);
00861 
00862                         if(row_vals[expires_col].val.int_val< (int)time(NULL))
00863                                 continue;
00864                 
00865                         sphere= NULL;
00866                         user.s= (char*)row_vals[user_col].val.string_val;
00867                         user.len= strlen(user.s);
00868                         domain.s= (char*)row_vals[domain_col].val.string_val;
00869                         domain.len= strlen(domain.s);
00870                         ev_str.s= (char*)row_vals[event_col].val.string_val;
00871                         ev_str.len= strlen(ev_str.s);
00872 
00873                         if(event_parser(ev_str.s, ev_str.len, &ev)< 0)
00874                         {
00875                                 LM_ERR("parsing event\n");
00876                                 free_event_params(ev.params.list, PKG_MEM_TYPE);
00877                                 goto error;
00878                         }
00879                         event= ev.type;
00880                         free_event_params(ev.params.list, PKG_MEM_TYPE);
00881 
00882                         if(uandd_to_uri(user, domain, &uri)< 0)
00883                         {
00884                                 LM_ERR("constructing uri\n");
00885                                 goto error;
00886                         }
00887                         /* insert in hash_table*/
00888         
00889                         if(sphere_enable && event== EVENT_PRESENCE )
00890                         {
00891                                 body.s= (char*)row_vals[body_col].val.string_val;
00892                                 body.len= strlen(body.s);
00893                                 sphere= extract_sphere(body);
00894                         }
00895 
00896                         if(insert_phtable(&uri, event, sphere)< 0)
00897                         {
00898                                 LM_ERR("inserting record in presentity hash table");
00899                                 pkg_free(uri.s);
00900                                 if(sphere)
00901                                         pkg_free(sphere);
00902                                 goto error;
00903                         }
00904                         if(sphere)
00905                                 pkg_free(sphere);
00906                         pkg_free(uri.s);
00907                 }
00908         } while((db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result)==1)
00909                         && (RES_ROW_N(result)>0));
00910 
00911         pa_dbf.free_result(pa_db, result);
00912 
00913         return 0;
00914 
00915 error:
00916         if(result)
00917                 pa_dbf.free_result(pa_db, result);
00918         return -1;      
00919 }
00920 
00921 char* extract_sphere(str body)
00922 {
00923 
00924         /* check for a rpid sphere element */
00925         xmlDocPtr doc= NULL;
00926         xmlNodePtr node;
00927         char* cont, *sphere= NULL;
00928         
00929 
00930         doc= xmlParseMemory(body.s, body.len);
00931         if(doc== NULL)
00932         {
00933                 LM_ERR("failed to parse xml body\n");
00934                 return NULL;
00935         }
00936 
00937         node= xmlNodeGetNodeByName(doc->children, "sphere", "rpid");
00938         
00939         if(node== NULL)
00940                 node= xmlNodeGetNodeByName(doc->children, "sphere", "r");
00941 
00942         if(node)
00943         {
00944                 LM_DBG("found sphere definition\n");
00945                 cont= (char*)xmlNodeGetContent(node);
00946                 if(cont== NULL)
00947                 {
00948                         LM_ERR("failed to extract sphere node content\n");
00949                         goto error;
00950                 }
00951                 sphere= (char*)pkg_malloc((strlen(cont)+ 1)*sizeof(char));
00952                 if(sphere== NULL)
00953                 {
00954                         xmlFree(cont);
00955                         ERR_MEM(PKG_MEM_STR);
00956                 }
00957                 strcpy(sphere, cont);
00958                 xmlFree(cont);
00959         }
00960         else
00961                 LM_DBG("didn't find sphere definition\n");
00962 
00963 error:
00964         xmlFreeDoc(doc);
00965 
00966         return sphere;
00967 }
00968 
00969 xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
00970                                                                                                         const char *ns)
00971 {
00972         xmlNodePtr cur = node;
00973         while (cur) {
00974                 xmlNodePtr match = NULL;
00975                 if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0) {
00976                         if (!ns || (cur->ns && xmlStrcasecmp(cur->ns->prefix,
00977                                                         (unsigned char*)ns) == 0))
00978                                 return cur;
00979                 }
00980                 match = xmlNodeGetNodeByName(cur->children, name, ns);
00981                 if (match)
00982                         return match;
00983                 cur = cur->next;
00984         }
00985         return NULL;
00986 }
00987 
00988 char* get_sphere(str* pres_uri)
00989 {
00990         unsigned int hash_code;
00991         char* sphere= NULL;
00992         pres_entry_t* p;
00993         db_key_t query_cols[6];
00994         db_val_t query_vals[6];
00995         db_key_t result_cols[6];
00996         db1_res_t *result = NULL;
00997         db_row_t *row= NULL;
00998         db_val_t *row_vals;
00999         int n_result_cols = 0;
01000         int n_query_cols = 0;
01001         struct sip_uri uri;
01002         str body;
01003 
01004 
01005         if(!sphere_enable)
01006                 return NULL;
01007 
01008         if ( publ_cache_enabled )
01009         {
01010                 /* search in hash table*/
01011                 hash_code= core_hash(pres_uri, NULL, phtable_size);
01012 
01013                 lock_get(&pres_htable[hash_code].lock);
01014 
01015                 p= search_phtable(pres_uri, EVENT_PRESENCE, hash_code);
01016 
01017                 if(p)
01018                 {
01019                         if(p->sphere)
01020                         {
01021                                 sphere= (char*)pkg_malloc(strlen(p->sphere)* sizeof(char));
01022                                 if(sphere== NULL)
01023                                 {
01024                                         lock_release(&pres_htable[hash_code].lock);
01025                                         ERR_MEM(PKG_MEM_STR);
01026                                 }
01027                                 strcpy(sphere, p->sphere);
01028                         }
01029                         lock_release(&pres_htable[hash_code].lock);
01030                         return sphere;
01031                 }
01032                 lock_release(&pres_htable[hash_code].lock);
01033         }
01034 
01035         if(parse_uri(pres_uri->s, pres_uri->len, &uri)< 0)
01036         {
01037                 LM_ERR("failed to parse presentity uri\n");
01038                 goto error;
01039         }
01040 
01041         query_cols[n_query_cols] = &str_domain_col;
01042         query_vals[n_query_cols].type = DB1_STR;
01043         query_vals[n_query_cols].nul = 0;
01044         query_vals[n_query_cols].val.str_val = uri.host;
01045         n_query_cols++;
01046 
01047         query_cols[n_query_cols] = &str_username_col;
01048         query_vals[n_query_cols].type = DB1_STR;
01049         query_vals[n_query_cols].nul = 0;
01050         query_vals[n_query_cols].val.str_val = uri.user;
01051         n_query_cols++;
01052 
01053         query_cols[n_query_cols] = &str_event_col;
01054         query_vals[n_query_cols].type = DB1_STR;
01055         query_vals[n_query_cols].nul = 0;
01056         query_vals[n_query_cols].val.str_val.s= "presence";
01057         query_vals[n_query_cols].val.str_val.len= 8;
01058         n_query_cols++;
01059 
01060         result_cols[n_result_cols++] = &str_body_col;
01061         
01062         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
01063         {
01064                 LM_ERR("in use_table\n");
01065                 return NULL;
01066         }
01067 
01068         static str query_str = str_init("received_time");
01069         if (pa_dbf.query (pa_db, query_cols, 0, query_vals,
01070                  result_cols, n_query_cols, n_result_cols, &query_str ,  &result) < 0) 
01071         {
01072                 LM_ERR("failed to query %.*s table\n", presentity_table.len, presentity_table.s);
01073                 if(result)
01074                         pa_dbf.free_result(pa_db, result);
01075                 return NULL;
01076         }
01077         
01078         if(result== NULL)
01079                 return NULL;
01080 
01081         if (result->n<=0 )
01082         {
01083                 LM_DBG("no published record found in database\n");
01084                 pa_dbf.free_result(pa_db, result);
01085                 return NULL;
01086         }
01087 
01088         row = &result->rows[result->n-1];
01089         row_vals = ROW_VALUES(row);
01090         if(row_vals[0].val.string_val== NULL)
01091         {
01092                 LM_ERR("NULL notify body record\n");
01093                 goto error;
01094         }
01095 
01096         body.s= (char*)row_vals[0].val.string_val;
01097         body.len= strlen(body.s);
01098         if(body.len== 0)
01099         {
01100                 LM_ERR("Empty notify body record\n");
01101                 goto error;
01102         }
01103         
01104         sphere= extract_sphere(body);
01105 
01106         pa_dbf.free_result(pa_db, result);
01107 
01108         return sphere;
01109 
01110 error:
01111         if(result)
01112                 pa_dbf.free_result(pa_db, result);
01113         return NULL;
01114 
01115 }
01116 
01117 int mark_presentity_for_delete(presentity_t *pres)
01118 {
01119         db_key_t query_cols[4], result_cols[1], update_cols[3];
01120         db_val_t query_vals[4], update_vals[3], *value;
01121         db_row_t *row;
01122         db1_res_t *result = NULL;
01123         int n_query_cols = 0, n_update_cols = 0;
01124         int ret = -1;
01125         str *cur_body = NULL, *new_body = NULL;
01126 
01127         if (pres->event->agg_nbody == NULL)
01128         {
01129                 /* Nothing clever to do here... just delete */
01130                 if (delete_presentity(pres) < 0)
01131                 {
01132                         LM_ERR("deleting presentity\n");
01133                         goto error;
01134                 }
01135                 goto done;
01136         }
01137 
01138         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
01139         {
01140                 LM_ERR("unsuccessful use table sql operation\n");
01141                 goto error;
01142         }
01143 
01144         query_cols[n_query_cols] = &str_username_col;
01145         query_vals[n_query_cols].type = DB1_STR;
01146         query_vals[n_query_cols].nul = 0;
01147         query_vals[n_query_cols].val.str_val = pres->user;
01148         n_query_cols++;
01149 
01150         query_cols[n_query_cols] = &str_domain_col;
01151         query_vals[n_query_cols].type = DB1_STR;
01152         query_vals[n_query_cols].nul = 0;
01153         query_vals[n_query_cols].val.str_val = pres->domain;
01154         n_query_cols++;
01155 
01156         query_cols[n_query_cols] = &str_event_col;
01157         query_vals[n_query_cols].type = DB1_STR;
01158         query_vals[n_query_cols].nul = 0;
01159         query_vals[n_query_cols].val.str_val = pres->event->name;
01160         n_query_cols++;
01161 
01162         query_cols[n_query_cols] = &str_etag_col;
01163         query_vals[n_query_cols].type = DB1_STR;
01164         query_vals[n_query_cols].nul = 0;
01165         query_vals[n_query_cols].val.str_val = pres->etag;
01166         n_query_cols++;
01167 
01168         result_cols[0] = &str_body_col;
01169 
01170         if (pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,
01171                                 n_query_cols, 1, 0, &result) < 0)
01172         {
01173                 LM_ERR("query failed\n");
01174                 goto error;
01175         }
01176 
01177         if (result == NULL)
01178         {
01179                 LM_ERR("bad result\n");
01180                 goto error;
01181         }
01182 
01183         if (RES_ROW_N(result) <= 0)
01184         {
01185                 /* Can happen when the timer and notifier processes clash */
01186                 LM_INFO("Found 0 presentities - expected 1\n");
01187                 goto done;
01188         }
01189 
01190         if (RES_ROW_N(result) > 1)
01191         {
01192                 /* More that one is prevented by DB constraint  - but handle
01193                    it anyway */
01194                 LM_ERR("Found %d presentities - expected 1\n", RES_ROW_N(result));
01195 
01196                 if (delete_presentity(pres) < 0)
01197                 {
01198                         LM_ERR("deleting presentity\n");
01199                         goto error;
01200                 }
01201 
01202                 /* Want the calling function to continue properly so do not
01203                    return an error */
01204                 goto done;
01205         }
01206 
01207         row = RES_ROWS(result);
01208         value = ROW_VALUES(row);
01209 
01210         if ((cur_body = (str *) pkg_malloc(sizeof(str))) == NULL)
01211         {
01212                 LM_ERR("allocating pkg memory\n");
01213                 goto error;
01214         }
01215         cur_body->s = (char *) value->val.string_val;
01216         cur_body->len = strlen (cur_body->s);
01217         if ((new_body = pres->event->agg_nbody(&pres->user, &pres->domain,
01218                                                 &cur_body, 1, 0)) == NULL)
01219         {
01220                 LM_ERR("preparing body\n");
01221                 goto error;
01222         }
01223 
01224         update_cols[n_update_cols] = &str_etag_col;
01225         update_vals[n_update_cols].type = DB1_STR;
01226         update_vals[n_update_cols].nul = 0;
01227         update_vals[n_update_cols].val.str_val = str_offline_etag_val;
01228         n_update_cols++;
01229 
01230         update_cols[n_update_cols] = &str_expires_col;
01231         update_vals[n_update_cols].type = DB1_INT;
01232         update_vals[n_update_cols].nul = 0;
01233         update_vals[n_update_cols].val.int_val = (int)time(NULL);
01234         n_update_cols++;
01235 
01236         update_cols[n_update_cols] = &str_body_col;
01237         update_vals[n_update_cols].type = DB1_STR;
01238         update_vals[n_update_cols].nul = 0;
01239         update_vals[n_update_cols].val.str_val.s = new_body->s;
01240         update_vals[n_update_cols].val.str_val.len = new_body->len;
01241         n_update_cols++;
01242 
01243         if (pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
01244                          update_vals, n_query_cols, n_update_cols) < 0)
01245         {
01246                 LM_ERR("unsuccessful sql update operation");
01247                 goto error;
01248         }
01249 
01250         if (pa_dbf.affected_rows)
01251                 ret = pa_dbf.affected_rows(pa_db);
01252         else
01253 done:
01254                 ret = 0;
01255 
01256 error:
01257         free_notify_body(new_body, pres->event);
01258         if (cur_body) pkg_free(cur_body);
01259         if (result) pa_dbf.free_result(pa_db, result);
01260         return ret;
01261 }
01262 
01263 int delete_presentity(presentity_t *pres)
01264 {
01265         db_key_t query_cols[4];
01266         db_val_t query_vals[4];
01267         int n_query_cols = 0;
01268 
01269         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
01270         {
01271                 LM_ERR("unsuccessful use table sql operation\n");
01272                 goto error;
01273         }
01274 
01275         query_cols[n_query_cols] = &str_username_col;
01276         query_vals[n_query_cols].type = DB1_STR;
01277         query_vals[n_query_cols].nul = 0;
01278         query_vals[n_query_cols].val.str_val = pres->user;
01279         n_query_cols++;
01280 
01281         query_cols[n_query_cols] = &str_domain_col;
01282         query_vals[n_query_cols].type = DB1_STR;
01283         query_vals[n_query_cols].nul = 0;
01284         query_vals[n_query_cols].val.str_val = pres->domain;
01285         n_query_cols++;
01286 
01287         query_cols[n_query_cols] = &str_event_col;
01288         query_vals[n_query_cols].type = DB1_STR;
01289         query_vals[n_query_cols].nul = 0;
01290         query_vals[n_query_cols].val.str_val = pres->event->name;
01291         n_query_cols++;
01292 
01293         query_cols[n_query_cols] = &str_etag_col;
01294         query_vals[n_query_cols].type = DB1_STR;
01295         query_vals[n_query_cols].nul = 0;
01296         query_vals[n_query_cols].val.str_val = pres->etag;
01297         n_query_cols++;
01298 
01299         if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0)
01300         {
01301                 LM_ERR("unsuccessful sql delete operation");
01302                 goto error;
01303         }
01304 
01305         if (pa_dbf.affected_rows)
01306                 return pa_dbf.affected_rows(pa_db);
01307         else
01308                 return 0;
01309 
01310 error:
01311         return -1;
01312 }
01313 
01314 int delete_offline_presentities(str *pres_uri, pres_ev_t *event)
01315 {
01316         db_key_t query_cols[4];
01317         db_val_t query_vals[4];
01318         int n_query_cols = 0;
01319         struct sip_uri uri;
01320 
01321         if (parse_uri(pres_uri->s, pres_uri->len, &uri) < 0)
01322         {
01323                 LM_ERR("failed to parse presentity uri\n");
01324                 goto error;
01325         }
01326 
01327         query_cols[n_query_cols] = &str_username_col;
01328         query_vals[n_query_cols].type = DB1_STR;
01329         query_vals[n_query_cols].nul = 0;
01330         query_vals[n_query_cols].val.str_val = uri.user;
01331         n_query_cols++;
01332 
01333         query_cols[n_query_cols] = &str_domain_col;
01334         query_vals[n_query_cols].type = DB1_STR;
01335         query_vals[n_query_cols].nul = 0;
01336         query_vals[n_query_cols].val.str_val = uri.host;
01337         n_query_cols++;
01338 
01339         query_cols[n_query_cols] = &str_event_col;
01340         query_vals[n_query_cols].type = DB1_STR;
01341         query_vals[n_query_cols].nul = 0;
01342         query_vals[n_query_cols].val.str_val = event->name;
01343         n_query_cols++;
01344 
01345         query_cols[n_query_cols] = &str_etag_col;
01346         query_vals[n_query_cols].type = DB1_STR;
01347         query_vals[n_query_cols].nul = 0;
01348         query_vals[n_query_cols].val.str_val = str_offline_etag_val;
01349         n_query_cols++;
01350 
01351         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
01352         {
01353                 LM_ERR("unsuccessful use table sql operation\n");
01354                 goto error;
01355         }
01356 
01357         if (pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0)
01358         {
01359                 LM_ERR("unsuccessful sql delete operation");
01360                 goto error;
01361         }
01362 
01363         if (pa_dbf.affected_rows)
01364                 return pa_dbf.affected_rows(pa_db);
01365         else
01366                 return 0;
01367 
01368 error:
01369         return -1;
01370 }