presence.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 
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <stdlib.h>
00044 #include <sys/types.h>
00045 #include <sys/ipc.h>
00046 #include <unistd.h>
00047 #include <fcntl.h>
00048 #include <time.h>
00049 
00050 #include "../../lib/srdb1/db.h"
00051 #include "../../sr_module.h"
00052 #include "../../dprint.h"
00053 #include "../../error.h"
00054 #include "../../ut.h"
00055 #include "../../parser/parse_to.h"
00056 #include "../../parser/parse_uri.h" 
00057 #include "../../parser/parse_content.h"
00058 #include "../../parser/parse_from.h"
00059 #include "../../mem/mem.h"
00060 #include "../../mem/shm_mem.h"
00061 #include "../../usr_avp.h"
00062 #include "../../modules/tm/tm_load.h"
00063 #include "../../modules/sl/sl.h"
00064 #include "../../pt.h"
00065 #include "../../lib/kmi/mi.h"
00066 #include "../../hashes.h"
00067 #include "../pua/hash.h"
00068 #include "presence.h"
00069 #include "publish.h"
00070 #include "subscribe.h"
00071 #include "event_list.h"
00072 #include "bind_presence.h"
00073 #include "notify.h"
00074 #include "../../mod_fix.h"
00075 #include "../../timer_proc.h"
00076 
00077 MODULE_VERSION
00078 
00079 #define S_TABLE_VERSION  3
00080 #define P_TABLE_VERSION  3
00081 #define ACTWATCH_TABLE_VERSION 11
00082 #define XCAP_TABLE_VERSION 4
00083 
00084 char *log_buf = NULL;
00085 static int clean_period=100;
00086 static int db_update_period=100;
00087 
00088 /* database connection */
00089 db1_con_t *pa_db = NULL;
00090 db_func_t pa_dbf;
00091 db1_con_t *pres_xcap_db = NULL;
00092 db_func_t pres_xcap_dbf;
00093 str presentity_table= str_init("presentity");
00094 str active_watchers_table = str_init("active_watchers");
00095 str watchers_table= str_init("watchers");
00096 str pres_xcap_table= str_init("xcap");
00097 
00098 int pres_fetch_rows = 500;
00099 int library_mode= 0;
00100 str server_address= {0, 0};
00101 evlist_t* EvList= NULL;
00102 
00103 /* to tag prefix */
00104 char* to_tag_pref = "10";
00105 
00106 /* TM bind */
00107 struct tm_binds tmb;
00108 /* SL API structure */
00109 sl_api_t slb;
00110 
00113 static int mod_init(void);
00114 static int child_init(int);
00115 static void destroy(void);
00116 int stored_pres_info(struct sip_msg* msg, char* pres_uri, char* s);
00117 static int fixup_presence(void** param, int param_no);
00118 static int fixup_subscribe(void** param, int param_no);
00119 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param);
00120 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param);
00121 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code,
00122                 subs_t** subs_array);
00123 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc);
00124 static int mi_child_init(void);
00125 static int w_pres_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2);
00126 static int w_pres_refresh_watchers(struct sip_msg *msg, char *puri,
00127                 char *pevent, char *ptype);
00128 static int w_pres_update_watchers(struct sip_msg *msg, char *puri,
00129                 char *pevent);
00130 static int fixup_refresh_watchers(void** param, int param_no);
00131 static int fixup_update_watchers(void** param, int param_no);
00132 static int fixup_update_presentity(void** param, int param_no);
00133 
00134 int counter =0;
00135 int pid = 0;
00136 char prefix='a';
00137 int startup_time=0;
00138 str db_url = {0, 0};
00139 str pres_xcap_db_url = {0, 0};
00140 int expires_offset = 0;
00141 int max_expires= 3600;
00142 int shtable_size= 9;
00143 shtable_t subs_htable= NULL;
00144 int subs_dbmode = WRITE_BACK;
00145 int sphere_enable= 0;
00146 int timeout_rm_subs = 1;
00147 int send_fast_notify = 1;
00148 int publ_cache_enabled = 1;
00149 int pres_waitn_time = 5;
00150 int pres_notifier_poll_rate = 10;
00151 int pres_notifier_processes = 1;
00152 int pres_integrated_xcap_server = 0;
00153 
00154 int *pres_notifier_id = NULL;
00155 
00156 int phtable_size= 9;
00157 phtable_t* pres_htable=NULL;
00158 
00159 static cmd_export_t cmds[]=
00160 {
00161         {"handle_publish",        (cmd_function)handle_publish,          0,
00162                 fixup_presence,0, REQUEST_ROUTE},
00163         {"handle_publish",        (cmd_function)handle_publish,          1,
00164                 fixup_presence, 0, REQUEST_ROUTE},
00165         {"handle_subscribe",      (cmd_function)handle_subscribe0,       0,
00166                 fixup_subscribe,0, REQUEST_ROUTE},
00167         {"handle_subscribe",      (cmd_function)w_handle_subscribe,      1,
00168                 fixup_subscribe,0, REQUEST_ROUTE},
00169         {"pres_auth_status",      (cmd_function)w_pres_auth_status,      2,
00170                 fixup_pvar_pvar, fixup_free_pvar_pvar, REQUEST_ROUTE},
00171         {"pres_refresh_watchers", (cmd_function)w_pres_refresh_watchers, 3,
00172                 fixup_refresh_watchers, 0, ANY_ROUTE},
00173         {"pres_update_watchers",  (cmd_function)w_pres_update_watchers,  2,
00174                 fixup_update_watchers, 0, ANY_ROUTE},
00175         {"pres_update_presentity", (cmd_function)pres_update_presentity, 3,
00176                 fixup_update_presentity, 0, ANY_ROUTE},
00177         {"bind_presence",         (cmd_function)bind_presence,           1,
00178                 0, 0, 0},
00179         { 0, 0, 0, 0, 0, 0}
00180 };
00181 
00182 static param_export_t params[]={
00183         { "db_url",                 STR_PARAM, &db_url.s},
00184         { "xcap_db_url",            STR_PARAM, &pres_xcap_db_url.s},
00185         { "presentity_table",       STR_PARAM, &presentity_table.s},
00186         { "active_watchers_table",  STR_PARAM, &active_watchers_table.s},
00187         { "watchers_table",         STR_PARAM, &watchers_table.s},
00188         { "xcap_table",             STR_PARAM, &pres_xcap_table.s},
00189         { "clean_period",           INT_PARAM, &clean_period },
00190         { "db_update_period",       INT_PARAM, &db_update_period },
00191         { "waitn_time",             INT_PARAM, &pres_waitn_time },
00192         { "notifier_poll_rate",     INT_PARAM, &pres_notifier_poll_rate },
00193         { "notifier_processes",     INT_PARAM, &pres_notifier_processes },
00194         { "to_tag_pref",            STR_PARAM, &to_tag_pref },
00195         { "expires_offset",         INT_PARAM, &expires_offset },
00196         { "max_expires",            INT_PARAM, &max_expires },
00197         { "server_address",         STR_PARAM, &server_address.s},
00198         { "subs_htable_size",       INT_PARAM, &shtable_size},
00199         { "pres_htable_size",       INT_PARAM, &phtable_size},
00200         { "subs_db_mode",           INT_PARAM, &subs_dbmode},
00201         { "publ_cache",             INT_PARAM, &publ_cache_enabled},
00202         { "enable_sphere_check",    INT_PARAM, &sphere_enable},
00203         { "timeout_rm_subs",        INT_PARAM, &timeout_rm_subs},
00204         { "send_fast_notify",       INT_PARAM, &send_fast_notify},
00205         { "fetch_rows",             INT_PARAM, &pres_fetch_rows},
00206         { "integrated_xcap_server", INT_PARAM, &pres_integrated_xcap_server},
00207     {0,0,0}
00208 };
00209 
00210 static mi_export_t mi_cmds[] = {
00211         { "refreshWatchers", mi_refreshWatchers,    0,  0,  mi_child_init},
00212         { "cleanup",         mi_cleanup,            0,  0,  mi_child_init},
00213         {  0,                0,                     0,  0,  0}
00214 };
00215 
00217 struct module_exports exports= {
00218         "presence",                     /* module name */
00219         DEFAULT_DLFLAGS,        /* dlopen flags */
00220         cmds,                           /* exported functions */
00221         params,                         /* exported parameters */
00222         0,                                      /* exported statistics */
00223         mi_cmds,                        /* exported MI functions */
00224         0,                                      /* exported pseudo-variables */
00225         0,                                      /* extra processes */
00226         mod_init,                       /* module initialization function */
00227         0,                              /* response handling function */
00228         (destroy_function) destroy,     /* destroy function */
00229         child_init                      /* per-child init function */
00230 };
00231 
00235 static int mod_init(void)
00236 {
00237         if(register_mi_mod(exports.name, mi_cmds)!=0)
00238         {
00239                 LM_ERR("failed to register MI commands\n");
00240                 return -1;
00241         }
00242 
00243         db_url.len = db_url.s ? strlen(db_url.s) : 0;
00244         LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
00245         presentity_table.len = strlen(presentity_table.s);
00246         active_watchers_table.len = strlen(active_watchers_table.s);
00247         watchers_table.len = strlen(watchers_table.s);
00248 
00249         if(pres_integrated_xcap_server == 1)
00250         {
00251                 pres_xcap_db_url.s = pres_xcap_db_url.s ? pres_xcap_db_url.s : db_url.s;
00252                 pres_xcap_db_url.len = strlen(pres_xcap_db_url.s);
00253                 pres_xcap_table.len = strlen(pres_xcap_table.s);
00254         }
00255 
00256         if(db_url.s== NULL)
00257                 library_mode= 1;
00258         else if(pres_integrated_xcap_server == 1)
00259         {
00260                 pres_xcap_db_url.s = pres_xcap_db_url.s ? pres_xcap_db_url.s : db_url.s;
00261                 pres_xcap_db_url.len = strlen(pres_xcap_db_url.s);
00262                 pres_xcap_table.len = strlen(pres_xcap_table.s);
00263         }
00264 
00265         EvList= init_evlist();
00266         if(!EvList){
00267                 LM_ERR("unsuccessful initialize event list\n");
00268                 return -1;
00269         }
00270 
00271         if(library_mode== 1)
00272         {
00273                 LM_DBG("Presence module used for API library purpose only\n");
00274                 return 0;
00275         }
00276 
00277         if(expires_offset<0)
00278                 expires_offset = 0;
00279         
00280         if(to_tag_pref==NULL || strlen(to_tag_pref)==0)
00281                 to_tag_pref="10";
00282 
00283         if(max_expires<= 0)
00284                 max_expires = 3600;
00285 
00286         if(server_address.s== NULL)
00287                 LM_DBG("server_address parameter not set in configuration file\n");
00288         
00289         if(server_address.s)
00290                 server_address.len= strlen(server_address.s);
00291         else
00292                 server_address.len= 0;
00293 
00294         /* bind the SL API */
00295         if (sl_load_api(&slb)!=0) {
00296                 LM_ERR("cannot bind to SL API\n");
00297                 return -1;
00298         }
00299 
00300         /* load all TM stuff */
00301         if(load_tm_api(&tmb)==-1)
00302         {
00303                 LM_ERR("Can't load tm functions. Module TM not loaded?\n");
00304                 return -1;
00305         }
00306         
00307         if(db_url.s== NULL)
00308         {
00309                 LM_ERR("database url not set!\n");
00310                 return -1;
00311         }
00312 
00313         /* binding to database module  */
00314         if (db_bind_mod(&db_url, &pa_dbf))
00315         {
00316                 LM_ERR("Database module not found\n");
00317                 return -1;
00318         }
00319 
00320         if (!DB_CAPABILITY(pa_dbf, DB_CAP_ALL))
00321         {
00322                 LM_ERR("Database module does not implement all functions"
00323                                 " needed by presence module\n");
00324                 return -1;
00325         }
00326 
00327         pa_db = pa_dbf.init(&db_url);
00328         if (!pa_db)
00329         {
00330                 LM_ERR("Connection to database failed\n");
00331                 return -1;
00332         }
00333         /*verify table versions */
00334         if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) ||
00335                 (db_check_table_version(&pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION) < 0)) {
00336                         LM_ERR("error during table version check\n");
00337                         return -1;
00338         }
00339         if(subs_dbmode != NO_DB &&
00340                 db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) {
00341                 LM_ERR("wrong table version for %s\n", active_watchers_table.s);
00342                 return -1;
00343         }
00344 
00345         if (pres_integrated_xcap_server == 1)
00346         {
00347                 if(pres_xcap_db_url.s== NULL)
00348                 {
00349                         LM_ERR("xcap database url not set!\n");
00350                         return -1;
00351                 }
00352 
00353                 if (db_bind_mod(&pres_xcap_db_url, &pres_xcap_dbf))
00354                 {
00355                         LM_ERR("Database module not found\n");
00356                         return -1;
00357                 }
00358 
00359                 if (!DB_CAPABILITY(pres_xcap_dbf, DB_CAP_ALL))
00360                 {
00361                         LM_ERR("Database module does not implement all functions"
00362                                         " needed by presence module\n");
00363                         return -1;
00364                 }
00365 
00366                 pres_xcap_db = pres_xcap_dbf.init(&pres_xcap_db_url);
00367                 if (!pres_xcap_db)
00368                 {
00369                         LM_ERR("Connection to database failed\n");
00370                         return -1;
00371                 }
00372 
00373                 if(db_check_table_version(&pres_xcap_dbf, pres_xcap_db, &pres_xcap_table, XCAP_TABLE_VERSION) < 0) {
00374                                 LM_ERR("error during table version check\n");
00375                                 return -1;
00376                 }
00377         }
00378 
00379         if(subs_dbmode != DB_ONLY) {
00380                 if(shtable_size< 1)
00381                         shtable_size= 512;
00382                 else
00383                         shtable_size= 1<< shtable_size;
00384 
00385                 subs_htable= new_shtable(shtable_size);
00386                 if(subs_htable== NULL)
00387                 {
00388                         LM_ERR(" initializing subscribe hash table\n");
00389                         return -1;
00390                 }
00391                 if(restore_db_subs()< 0)
00392                 {
00393                         LM_ERR("restoring subscribe info from database\n");
00394                         return -1;
00395                 }
00396         }
00397 
00398         if(publ_cache_enabled) {
00399                 if(phtable_size< 1)
00400                         phtable_size= 256;
00401                 else
00402                         phtable_size= 1<< phtable_size;
00403 
00404                 pres_htable= new_phtable();
00405                 if(pres_htable== NULL)
00406                 {
00407                         LM_ERR("initializing presentity hash table\n");
00408                         return -1;
00409                 }
00410 
00411                 if(pres_htable_restore()< 0)
00412                 {
00413                         LM_ERR("filling in presentity hash table from database\n");
00414                         return -1;
00415                 }
00416         }
00417 
00418         startup_time = (int) time(NULL);
00419         if(clean_period>0)
00420         {
00421                 register_timer(msg_presentity_clean, 0, clean_period);
00422                 register_timer(msg_watchers_clean, 0, clean_period);
00423         }
00424 
00425         if(db_update_period>0)
00426                 register_timer(timer_db_update, 0, db_update_period);
00427 
00428         if (pres_waitn_time <= 0)
00429                 pres_waitn_time = 5;
00430 
00431         if (pres_notifier_poll_rate <= 0)
00432                 pres_notifier_poll_rate = 10;
00433 
00434         if (pres_notifier_processes < 0 || subs_dbmode != DB_ONLY)
00435                 pres_notifier_processes = 0;
00436 
00437         if (pres_notifier_processes > 0)
00438         {
00439                 if ((pres_notifier_id = shm_malloc(sizeof(int) * pres_notifier_processes)) == NULL)
00440                 {
00441                         LM_ERR("allocating shared memory\n");
00442                         return -1;
00443                 }
00444 
00445                 register_basic_timers(pres_notifier_processes);
00446         }
00447 
00448         pa_dbf.close(pa_db);
00449         pa_db = NULL;
00450 
00451         if (pres_integrated_xcap_server == 1)
00452         {
00453                 pres_xcap_dbf.close(pres_xcap_db);
00454                 pres_xcap_db = NULL;
00455         }
00456 
00457         return 0;
00458 }
00459 
00463 static int child_init(int rank)
00464 {
00465         if (rank==PROC_INIT || rank==PROC_TCP_MAIN)
00466                 return 0;
00467 
00468         if (rank == PROC_MAIN)
00469         {
00470                 int i;
00471 
00472                 for (i = 0; i < pres_notifier_processes; i++)
00473                 {
00474                         char tmp[21];
00475                         snprintf(tmp, 21, "PRESENCE NOTIFIER %d", i);
00476                         pres_notifier_id[i] = i;
00477 
00478                         if (fork_basic_utimer(PROC_TIMER, tmp, 1,
00479                                                 pres_timer_send_notify,
00480                                                 &pres_notifier_id[i],
00481                                                 1000000/pres_notifier_poll_rate) < 0)
00482                         {
00483                                 LM_ERR("Failed to start PRESENCE NOTIFIER %d\n", i);
00484                                 return -1;
00485                         }
00486                 }
00487 
00488                 return 0;
00489         }
00490 
00491         pid = my_pid();
00492         
00493         if(library_mode)
00494                 return 0;
00495 
00496         if (pa_dbf.init==0)
00497         {
00498                 LM_CRIT("child_init: database not bound\n");
00499                 return -1;
00500         }
00501         /* Do not pool the connections where possible when running notifier
00502        processes. */
00503         if (pres_notifier_processes > 0 && pa_dbf.init2)
00504                 pa_db = pa_dbf.init2(&db_url, DB_POOLING_NONE);
00505         else
00506                 pa_db = pa_dbf.init(&db_url);
00507         if (!pa_db)
00508         {
00509                 LM_ERR("child %d: unsuccessful connecting to database\n", rank);
00510                 return -1;
00511         }
00512         
00513         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
00514         {
00515                 LM_ERR( "child %d:unsuccessful use_table presentity_table\n", rank);
00516                 return -1;
00517         }
00518 
00519         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)  
00520         {
00521                 LM_ERR( "child %d:unsuccessful use_table active_watchers_table\n",
00522                                 rank);
00523                 return -1;
00524         }
00525 
00526         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)  
00527         {
00528                 LM_ERR( "child %d:unsuccessful use_table watchers_table\n", rank);
00529                 return -1;
00530         }
00531 
00532         if (pres_integrated_xcap_server == 1)
00533         {
00534                 if (pres_xcap_dbf.init==0)
00535                 {
00536                         LM_CRIT("child_init: database not bound\n");
00537                         return -1;
00538                 }
00539                 if (pres_xcap_db)
00540                         return 0;
00541                 pres_xcap_db = pres_xcap_dbf.init(&pres_xcap_db_url);
00542                 if (!pres_xcap_db)
00543                 {
00544                         LM_ERR("child %d: unsuccessful connecting to database\n", rank);
00545                         return -1;
00546                 }
00547         
00548                 if (pres_xcap_dbf.use_table(pres_xcap_db, &pres_xcap_table) < 0)
00549                 {
00550                         LM_ERR( "child %d:unsuccessful use_table xcap_table\n", rank);
00551                         return -1;
00552                 }
00553         }
00554 
00555         LM_DBG("child %d: Database connection opened successfully\n", rank);
00556         
00557         return 0;
00558 }
00559 
00560 static int mi_child_init(void)
00561 {
00562         if(library_mode)
00563                 return 0;
00564 
00565         if (pa_dbf.init==0)
00566         {
00567                 LM_CRIT("database not bound\n");
00568                 return -1;
00569         }
00570         /* Do not pool the connections where possible when running notifier
00571        processes. */
00572         if (pres_notifier_processes > 0 && pa_dbf.init2)
00573                 pa_db = pa_dbf.init2(&db_url, DB_POOLING_NONE);
00574         else
00575                 pa_db = pa_dbf.init(&db_url);
00576         if (!pa_db)
00577         {
00578                 LM_ERR("connecting database\n");
00579                 return -1;
00580         }
00581         
00582         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
00583         {
00584                 LM_ERR( "unsuccessful use_table presentity_table\n");
00585                 return -1;
00586         }
00587 
00588         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
00589         {
00590                 LM_ERR( "unsuccessful use_table active_watchers_table\n");
00591                 return -1;
00592         }
00593 
00594         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)
00595         {
00596                 LM_ERR( "unsuccessful use_table watchers_table\n");
00597                 return -1;
00598         }
00599 
00600         if (pres_integrated_xcap_server == 1)
00601         {
00602                 if (pres_xcap_dbf.init==0)
00603                 {
00604                         LM_CRIT("database not bound\n");
00605                         return -1;
00606                 }
00607                 if (pres_xcap_db)
00608                         return 0;
00609                 pres_xcap_db = pres_xcap_dbf.init(&db_url);
00610                 if (!pres_xcap_db)
00611                 {
00612                         LM_ERR("connecting database\n");
00613                         return -1;
00614                 }
00615         
00616                 if (pres_xcap_dbf.use_table(pres_xcap_db, &pres_xcap_table) < 0)
00617                 {
00618                         LM_ERR( "unsuccessful use_table xcap_table\n");
00619                         return -1;
00620                 }
00621         }
00622 
00623         LM_DBG("Database connection opened successfully\n");
00624         return 0;
00625 }
00626 
00627 
00628 /*
00629  * destroy function
00630  */
00631 static void destroy(void)
00632 {
00633         if(subs_htable && subs_dbmode == WRITE_BACK) {
00634                 /* open database connection */
00635                 pa_db = pa_dbf.init(&db_url);
00636                 if (!pa_db) {
00637                         LM_ERR("mod_destroy: unsuccessful connecting to database\n");
00638                 } else
00639                         timer_db_update(0, 0);
00640         }
00641 
00642         if(subs_htable)
00643                 destroy_shtable(subs_htable, shtable_size);
00644         
00645         if(pres_htable)
00646                 destroy_phtable();
00647 
00648         if(pa_db && pa_dbf.close)
00649                 pa_dbf.close(pa_db);
00650 
00651         if(pres_xcap_db && pres_xcap_dbf.close)
00652                 pres_xcap_dbf.close(pres_xcap_db);
00653 
00654         if (pres_notifier_id != NULL)
00655                 shm_free(pres_notifier_id);
00656 
00657         destroy_evlist();
00658 }
00659 
00660 static int fixup_presence(void** param, int param_no)
00661 {
00662         pv_elem_t *model;
00663         str s;
00664 
00665         if(library_mode)
00666         {
00667                 LM_ERR("Bad config - you can not call 'handle_publish' function"
00668                                 " (db_url not set)\n");
00669                 return -1;
00670         }
00671         if(param_no== 0)
00672                 return 0;
00673 
00674         if(*param)
00675         {
00676                 s.s = (char*)(*param); s.len = strlen(s.s);
00677                 if(pv_parse_format(&s, &model)<0)
00678                 {
00679                         LM_ERR( "wrong format[%s]\n",(char*)(*param));
00680                         return E_UNSPEC;
00681                 }
00682  
00683                 *param = (void*)model;
00684                 return 0;
00685         }
00686         LM_ERR( "null format\n");
00687         return E_UNSPEC;
00688 }
00689 
00690 static int fixup_subscribe(void** param, int param_no)
00691 {
00692 
00693         if(library_mode)
00694         {
00695                 LM_ERR("Bad config - you can not call 'handle_subscribe' function"
00696                                 " (db_url not set)\n");
00697                 return -1;
00698         }
00699         if (param_no == 1) {
00700                 return fixup_spve_null(param, 1);
00701         }
00702         return 0;
00703 }
00704 
00705 int pres_refresh_watchers(str *pres, str *event, int type)
00706 {
00707         pres_ev_t *ev;
00708         struct sip_uri uri;
00709         str *rules_doc= NULL;
00710         int result;
00711 
00712         ev= contains_event(event, NULL);
00713         if(ev==NULL)
00714         {
00715                 LM_ERR("wrong event parameter\n");
00716                 return -1;
00717         }
00718 
00719         if(type==0)
00720         {
00721                 /* if a request to refresh watchers authorization */
00722                 if(ev->get_rules_doc==NULL)
00723                 {
00724                         LM_ERR("wrong request for a refresh watchers authorization status"
00725                                         "for an event that does not require authorization\n");
00726                         goto error;
00727                 }
00728 
00729                 if(parse_uri(pres->s, pres->len, &uri)<0)
00730                 {
00731                         LM_ERR("parsing uri [%.*s]\n", pres->len, pres->s);
00732                         goto error;
00733                 }
00734 
00735                 result= ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
00736                 if(result<0 || rules_doc==NULL || rules_doc->s==NULL)
00737                 {
00738                         LM_ERR("no rules doc found for the user\n");
00739                         goto error;
00740                 }
00741 
00742                 if(update_watchers_status(*pres, ev, rules_doc)<0)
00743                 {
00744                         LM_ERR("failed to update watchers\n");
00745                         goto error;
00746                 }
00747 
00748                 pkg_free(rules_doc->s);
00749                 pkg_free(rules_doc);
00750                 rules_doc = NULL;
00751 
00752         } else {
00753                 /* if a request to refresh notified info */
00754                 if(query_db_notify(pres, ev, NULL)< 0)
00755                 {
00756                         LM_ERR("sending Notify requests\n");
00757                         goto error;
00758                 }
00759 
00760         }
00761         return 0;
00762 
00763 error:
00764         if(rules_doc)
00765         {
00766                 if(rules_doc->s)
00767                         pkg_free(rules_doc->s);
00768                 pkg_free(rules_doc);
00769         }
00770         return -1;
00771 }
00772 
00781 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param)
00782 {
00783         struct mi_node* node= NULL;
00784         str pres_uri, event;
00785         unsigned int refresh_type;
00786 
00787         LM_DBG("start\n");
00788         
00789         node = cmd->node.kids;
00790         if(node == NULL)
00791                 return 0;
00792 
00793         /* Get presentity URI */
00794         pres_uri = node->value;
00795         if(pres_uri.s == NULL || pres_uri.len== 0)
00796         {
00797                 LM_ERR( "empty uri\n");
00798                 return init_mi_tree(404, "Empty presentity URI", 20);
00799         }
00800         
00801         node = node->next;
00802         if(node == NULL)
00803                 return 0;
00804         event= node->value;
00805         if(event.s== NULL || event.len== 0)
00806         {
00807                 LM_ERR( "empty event parameter\n");
00808                 return init_mi_tree(400, "Empty event parameter", 21);
00809         }
00810         LM_DBG("event '%.*s'\n",  event.len, event.s);
00811         
00812         node = node->next;
00813         if(node == NULL)
00814                 return 0;
00815         if(node->value.s== NULL || node->value.len== 0)
00816         {
00817                 LM_ERR( "empty refresh type parameter\n");
00818                 return init_mi_tree(400, "Empty refresh type parameter", 28);
00819         }
00820         if(str2int(&node->value, &refresh_type)< 0)
00821         {
00822                 LM_ERR("converting string to int\n");
00823                 goto error;
00824         }
00825 
00826         if(node->next!= NULL)
00827         {
00828                 LM_ERR( "Too many parameters\n");
00829                 return init_mi_tree(400, "Too many parameters", 19);
00830         }
00831 
00832         if(pres_refresh_watchers(&pres_uri, &event, refresh_type)<0)
00833                 return 0;
00834         
00835         return init_mi_tree(200, "OK", 2);
00836 
00837 error:
00838         return 0;
00839 }
00840 
00841 /* 
00842  *  mi cmd: cleanup
00843  *              * */
00844 
00845 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param)
00846 {
00847         LM_DBG("mi_cleanup:start\n");
00848         
00849         (void)msg_watchers_clean(0,0);
00850         (void)msg_presentity_clean(0,0);
00851         (void)timer_db_update(0,0);
00852                 
00853         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00854 }
00855 
00856 int pres_update_status(subs_t subs, str reason, db_key_t* query_cols,
00857         db_val_t* query_vals, int n_query_cols, subs_t** subs_array)
00858 {
00859         db_key_t update_cols[5];
00860         db_val_t update_vals[5];
00861         int n_update_cols= 0;
00862         int u_status_col, u_reason_col, q_wuser_col, q_wdomain_col;
00863         int status;
00864         query_cols[q_wuser_col=n_query_cols]= &str_watcher_username_col;
00865         query_vals[n_query_cols].nul= 0;
00866         query_vals[n_query_cols].type= DB1_STR;
00867         n_query_cols++;
00868 
00869         query_cols[q_wdomain_col=n_query_cols]= &str_watcher_domain_col;
00870         query_vals[n_query_cols].nul= 0;
00871         query_vals[n_query_cols].type= DB1_STR;
00872         n_query_cols++;
00873 
00874         update_cols[u_status_col= n_update_cols]= &str_status_col;
00875         update_vals[u_status_col].nul= 0;
00876         update_vals[u_status_col].type= DB1_INT;
00877         n_update_cols++;
00878 
00879         update_cols[u_reason_col= n_update_cols]= &str_reason_col;
00880         update_vals[u_reason_col].nul= 0;
00881         update_vals[u_reason_col].type= DB1_STR;
00882         n_update_cols++;
00883 
00884         status= subs.status;
00885         if(subs.event->get_auth_status(&subs)< 0)
00886         {
00887                 LM_ERR( "getting status from rules document\n");
00888                 return -1;
00889         }
00890         LM_DBG("subs.status= %d\n", subs.status);
00891         if(get_status_str(subs.status)== NULL)
00892         {
00893                 LM_ERR("wrong status: %d\n", subs.status);
00894                 return -1;
00895         }
00896 
00897         if(subs.status!= status || reason.len!= subs.reason.len ||
00898                 (reason.s && subs.reason.s && strncmp(reason.s, subs.reason.s,
00899                                                                                           reason.len)))
00900         {
00901                 /* update in watchers_table */
00902                 query_vals[q_wuser_col].val.str_val= subs.watcher_user; 
00903                 query_vals[q_wdomain_col].val.str_val= subs.watcher_domain; 
00904 
00905                 /* if status is no longer ACTIVE, switch to terminated */
00906                 if(subs.status!=status && status==ACTIVE_STATUS)
00907                 {
00908                         subs.status = TERMINATED_STATUS;
00909                         subs.reason.s = get_status_str(TERMINATED_STATUS);
00910                         subs.reason.len = strlen(subs.reason.s);
00911                 }
00912 
00913                 update_vals[u_status_col].val.int_val= subs.status;
00914                 update_vals[u_reason_col].val.str_val= subs.reason;
00915                 
00916                 if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
00917                 {
00918                         LM_ERR( "in use_table\n");
00919                         return -1;
00920                 }
00921 
00922                 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
00923                                         update_vals, n_query_cols, n_update_cols)< 0)
00924                 {
00925                         LM_ERR( "in sql update\n");
00926                         return -1;
00927                 }
00928                 /* save in the list all affected dialogs */
00929                 /* if status switches to terminated -> delete dialog */
00930                 if(update_pw_dialogs(&subs, subs.db_flag, subs_array)< 0)
00931                 {
00932                         LM_ERR( "extracting dialogs from [watcher]=%.*s@%.*s to"
00933                                 " [presentity]=%.*s\n", subs.watcher_user.len, subs.watcher_user.s,
00934                                 subs.watcher_domain.len, subs.watcher_domain.s, subs.pres_uri.len,
00935                                 subs.pres_uri.s);
00936                         return -1;
00937                 }
00938         }
00939     return 0;
00940 }
00941 
00942 int pres_db_delete_status(subs_t* s)
00943 {
00944     int n_query_cols= 0;
00945     db_key_t query_cols[5];
00946     db_val_t query_vals[5];
00947 
00948     if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
00949     {
00950         LM_ERR("sql use table failed\n");
00951         return -1;
00952     }
00953 
00954     query_cols[n_query_cols]= &str_event_col;
00955     query_vals[n_query_cols].nul= 0;
00956     query_vals[n_query_cols].type= DB1_STR;
00957     query_vals[n_query_cols].val.str_val= s->event->name ;
00958     n_query_cols++;
00959 
00960     query_cols[n_query_cols]= &str_presentity_uri_col;
00961     query_vals[n_query_cols].nul= 0;
00962     query_vals[n_query_cols].type= DB1_STR;
00963     query_vals[n_query_cols].val.str_val= s->pres_uri;
00964     n_query_cols++;
00965 
00966     query_cols[n_query_cols]= &str_watcher_username_col;
00967     query_vals[n_query_cols].nul= 0;
00968     query_vals[n_query_cols].type= DB1_STR;
00969     query_vals[n_query_cols].val.str_val= s->watcher_user;
00970     n_query_cols++;
00971 
00972     query_cols[n_query_cols]= &str_watcher_domain_col;
00973     query_vals[n_query_cols].nul= 0;
00974     query_vals[n_query_cols].type= DB1_STR;
00975     query_vals[n_query_cols].val.str_val= s->watcher_domain;
00976     n_query_cols++;
00977 
00978     if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)< 0)
00979     {
00980         LM_ERR("sql delete failed\n");
00981         return -1;
00982     }
00983     return 0;
00984 
00985 }
00986 
00987 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc)
00988 {
00989         subs_t subs;
00990         db_key_t query_cols[6], result_cols[5];
00991         db_val_t query_vals[6];
00992         int n_result_cols= 0, n_query_cols = 0;
00993         db1_res_t* result= NULL;
00994         db_row_t *row;
00995         db_val_t *row_vals ;
00996         int i;
00997         str w_user, w_domain, reason= {0, 0};
00998         unsigned int status;
00999         int status_col, w_user_col, w_domain_col, reason_col;
01000         subs_t* subs_array= NULL,* s;
01001         unsigned int hash_code;
01002         int err_ret= -1;
01003         int n= 0;
01004 
01005         typedef struct ws
01006         {
01007                 int status;
01008                 str reason;
01009                 str w_user;
01010                 str w_domain;
01011         }ws_t;
01012         ws_t* ws_list= NULL;
01013 
01014         LM_DBG("start\n");
01015 
01016         if(ev->content_type.s== NULL)
01017         {
01018                 ev= contains_event(&ev->name, NULL);
01019                 if(ev== NULL)
01020                 {
01021                         LM_ERR("wrong event parameter\n");
01022                         return 0;
01023                 }
01024         }
01025 
01026         subs.pres_uri= pres_uri;
01027         subs.event= ev;
01028         subs.auth_rules_doc= rules_doc;
01029 
01030         /* update in watchers_table */
01031         query_cols[n_query_cols]= &str_presentity_uri_col;
01032         query_vals[n_query_cols].nul= 0;
01033         query_vals[n_query_cols].type= DB1_STR;
01034         query_vals[n_query_cols].val.str_val= pres_uri;
01035         n_query_cols++;
01036 
01037         query_cols[n_query_cols]= &str_event_col;
01038         query_vals[n_query_cols].nul= 0;
01039         query_vals[n_query_cols].type= DB1_STR;
01040         query_vals[n_query_cols].val.str_val= ev->name;
01041         n_query_cols++;
01042 
01043         result_cols[status_col= n_result_cols++]= &str_status_col;
01044         result_cols[reason_col= n_result_cols++]= &str_reason_col;
01045         result_cols[w_user_col= n_result_cols++]= &str_watcher_username_col;
01046         result_cols[w_domain_col= n_result_cols++]= &str_watcher_domain_col;
01047 
01048         if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
01049         {
01050                 LM_ERR( "in use_table\n");
01051                 goto done;
01052         }
01053 
01054         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,n_query_cols,
01055                                 n_result_cols, 0, &result)< 0)
01056         {
01057                 LM_ERR( "in sql query\n");
01058                 goto done;
01059         }
01060         if(result== NULL)
01061                 return 0;
01062 
01063         if(result->n<= 0)
01064         {
01065                 err_ret= 0;
01066                 goto done;
01067         }
01068 
01069         LM_DBG("found %d record-uri in watchers_table\n", result->n);
01070         hash_code= core_hash(&pres_uri, &ev->name, shtable_size);
01071         subs.db_flag= hash_code;
01072 
01073         /*must do a copy as sphere_check requires database queries */
01074         if(sphere_enable)
01075         {
01076                 n= result->n;
01077                 ws_list= (ws_t*)pkg_malloc(n * sizeof(ws_t));
01078                 if(ws_list== NULL)
01079                 {
01080                         LM_ERR("No more private memory\n");
01081                         goto done;
01082                 }
01083                 memset(ws_list, 0, n * sizeof(ws_t));
01084 
01085                 for(i= 0; i< result->n ; i++)
01086                 {
01087                         row= &result->rows[i];
01088                         row_vals = ROW_VALUES(row);
01089 
01090                         status= row_vals[status_col].val.int_val;
01091         
01092                         reason.s= (char*)row_vals[reason_col].val.string_val;
01093                         reason.len= reason.s?strlen(reason.s):0;
01094 
01095                         w_user.s= (char*)row_vals[w_user_col].val.string_val;
01096                         w_user.len= strlen(w_user.s);
01097 
01098                         w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
01099                         w_domain.len= strlen(w_domain.s);
01100 
01101                         if(reason.len)
01102                         {
01103                                 ws_list[i].reason.s = (char*)pkg_malloc(reason.len* sizeof(char));
01104                                 if(ws_list[i].reason.s== NULL)
01105                                 {  
01106                                         LM_ERR("No more private memory\n");
01107                                         goto done;
01108                                 }
01109                                 memcpy(ws_list[i].reason.s, reason.s, reason.len);
01110                                 ws_list[i].reason.len= reason.len;
01111                         }
01112                         else
01113                                 ws_list[i].reason.s= NULL;
01114             
01115                         ws_list[i].w_user.s = (char*)pkg_malloc(w_user.len* sizeof(char));
01116                         if(ws_list[i].w_user.s== NULL)
01117                         {
01118                                 LM_ERR("No more private memory\n");
01119                                 goto done;
01120 
01121                         }
01122                         memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
01123                         ws_list[i].w_user.len= w_user.len;
01124                 
01125                          ws_list[i].w_domain.s = (char*)pkg_malloc(w_domain.len* sizeof(char));
01126                         if(ws_list[i].w_domain.s== NULL)
01127                         {
01128                                 LM_ERR("No more private memory\n");
01129                                 goto done;
01130                         }
01131                         memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
01132                         ws_list[i].w_domain.len= w_domain.len;
01133                         
01134                         ws_list[i].status= status;
01135                 }
01136 
01137                 pa_dbf.free_result(pa_db, result);
01138                 result= NULL;
01139 
01140                 for(i=0; i< n; i++)
01141                 {
01142                         subs.watcher_user = ws_list[i].w_user;
01143                         subs.watcher_domain = ws_list[i].w_domain;
01144                         subs.status = ws_list[i].status;
01145                         memset(&subs.reason, 0, sizeof(str));
01146 
01147                         if( pres_update_status(subs, reason, query_cols, query_vals,
01148                                         n_query_cols, &subs_array)< 0)
01149                         {
01150                                 LM_ERR("failed to update watcher status\n");
01151                                 goto done;
01152                         }
01153 
01154                 }
01155         
01156                 for(i=0; i< n; i++)
01157                 {
01158                         pkg_free(ws_list[i].w_user.s);
01159                         pkg_free(ws_list[i].w_domain.s);
01160                         if(ws_list[i].reason.s)
01161                                 pkg_free(ws_list[i].reason.s);
01162                 }
01163                 ws_list= NULL;
01164 
01165                 goto send_notify;
01166 
01167         }
01168         
01169         for(i = 0; i< result->n; i++)
01170         {
01171                 row= &result->rows[i];
01172                 row_vals = ROW_VALUES(row);
01173 
01174                 status= row_vals[status_col].val.int_val;
01175         
01176                 reason.s= (char*)row_vals[reason_col].val.string_val;
01177                 reason.len= reason.s?strlen(reason.s):0;
01178 
01179                 w_user.s= (char*)row_vals[w_user_col].val.string_val;
01180                 w_user.len= strlen(w_user.s);
01181 
01182                 w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
01183                 w_domain.len= strlen(w_domain.s);
01184 
01185                 subs.watcher_user= w_user;
01186                 subs.watcher_domain= w_domain;
01187                 subs.status= status;
01188                 memset(&subs.reason, 0, sizeof(str));
01189 
01190                 if( pres_update_status(subs,reason, query_cols, query_vals,
01191                                         n_query_cols, &subs_array)< 0)
01192                 {
01193                         LM_ERR("failed to update watcher status\n");
01194                         goto done;
01195                 }
01196         }
01197 
01198         pa_dbf.free_result(pa_db, result);
01199         result= NULL;
01200 
01201 send_notify:
01202 
01203         if (pres_notifier_processes == 0)
01204         {
01205                 s= subs_array;
01206 
01207                 while(s)
01208                 {
01209                         if(notify(s, NULL, NULL, 0)< 0)
01210                         {
01211                                 LM_ERR( "sending Notify request\n");
01212                                 goto done;
01213                         }
01214 
01215                         /* delete from database also */
01216                         if(s->status== TERMINATED_STATUS)
01217                         {
01218                                 if(pres_db_delete_status(s)<0)
01219                                 {
01220                                         LM_ERR("failed to delete terminated "
01221                                                 "dialog from database\n");
01222                                         goto done;
01223                                 }
01224                         }
01225 
01226                         s= s->next;
01227                 }
01228         }
01229 
01230         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
01231         return 0;
01232 
01233 done:
01234         if(result)
01235                 pa_dbf.free_result(pa_db, result);
01236         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
01237         if(ws_list)
01238         {
01239                 for(i= 0; i< n; i++)
01240                 {
01241                         if(ws_list[i].w_user.s)
01242                                 pkg_free(ws_list[i].w_user.s);
01243                         else
01244                                 break;
01245                         if(ws_list[i].w_domain.s)
01246                                 pkg_free(ws_list[i].w_domain.s);
01247                         if(ws_list[i].reason.s)
01248                                 pkg_free(ws_list[i].reason.s);
01249                 }
01250         }
01251         return err_ret;
01252 }
01253 
01254 /********************************************************************************/
01255 
01256 static int update_pw_dialogs_dbonlymode(subs_t* subs, subs_t** subs_array)
01257 {
01258         db_key_t query_cols[5], db_cols[3];
01259         db_val_t query_vals[5], db_vals[3];
01260         db_key_t result_cols[24];
01261         int n_query_cols=0, n_result_cols=0, n_update_cols=0;
01262         int event_col, pres_uri_col, watcher_user_col, watcher_domain_col;
01263         int r_pres_uri_col,r_to_user_col,r_to_domain_col;
01264         int r_from_user_col,r_from_domain_col,r_callid_col;
01265         int r_to_tag_col,r_from_tag_col,r_sockinfo_col;
01266         int r_event_id_col,r_local_contact_col,r_contact_col;
01267         int r_record_route_col, r_reason_col;
01268         int r_event_col, r_local_cseq_col, r_remote_cseq_col;
01269         int r_status_col, r_version_col;
01270         int r_expires_col, r_watcher_user_col, r_watcher_domain_col;
01271         db1_res_t *result= NULL;
01272         db_val_t *row_vals;
01273         db_row_t *rows;
01274         int nr_rows, loop;
01275         subs_t s, *cs;
01276         str ev_sname;
01277 
01278         if(pa_db == NULL)
01279         {
01280                 LM_ERR("null database connection\n");
01281                 return(-1);
01282         }
01283 
01284         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
01285         {
01286                 LM_ERR("use table failed\n");
01287                 return(-1);
01288         }
01289 
01290         query_cols[event_col=n_query_cols]= &str_event_col;
01291         query_vals[event_col].nul= 0;
01292         query_vals[event_col].type= DB1_STR;
01293         query_vals[event_col].val.str_val= subs->event->name ;
01294         n_query_cols++;
01295 
01296         query_cols[pres_uri_col=n_query_cols]= &str_presentity_uri_col;
01297         query_vals[pres_uri_col].nul= 0;
01298         query_vals[pres_uri_col].type= DB1_STR;
01299         query_vals[pres_uri_col].val.str_val= subs->pres_uri;
01300         n_query_cols++;
01301 
01302         query_cols[watcher_user_col=n_query_cols]= &str_watcher_username_col;
01303         query_vals[watcher_user_col].nul= 0;
01304         query_vals[watcher_user_col].type= DB1_STR;
01305         query_vals[watcher_user_col].val.str_val= subs->watcher_user;
01306         n_query_cols++;
01307 
01308         query_cols[watcher_domain_col=n_query_cols]= &str_watcher_domain_col;
01309         query_vals[watcher_domain_col].nul= 0;
01310         query_vals[watcher_domain_col].type= DB1_STR;
01311         query_vals[watcher_domain_col].val.str_val= subs->watcher_domain;
01312         n_query_cols++;
01313 
01314 
01315         result_cols[r_to_user_col=n_result_cols++] = &str_to_user_col;
01316         result_cols[r_to_domain_col=n_result_cols++] = &str_to_domain_col;
01317         result_cols[r_from_user_col=n_result_cols++] = &str_from_user_col;
01318         result_cols[r_from_domain_col=n_result_cols++] = &str_from_domain_col;
01319         result_cols[r_watcher_user_col=n_result_cols++] = &str_watcher_username_col;
01320         result_cols[r_watcher_domain_col=n_result_cols++] = &str_watcher_domain_col;
01321         result_cols[r_callid_col=n_result_cols++] = &str_callid_col;
01322         result_cols[r_to_tag_col=n_result_cols++] = &str_to_tag_col;
01323         result_cols[r_from_tag_col=n_result_cols++] = &str_from_tag_col;
01324         result_cols[r_sockinfo_col=n_result_cols++] = &str_socket_info_col;
01325         result_cols[r_event_id_col=n_result_cols++] = &str_event_id_col;
01326         result_cols[r_local_contact_col=n_result_cols++] = &str_local_contact_col;
01327         result_cols[r_record_route_col=n_result_cols++] = &str_record_route_col;
01328         result_cols[r_reason_col=n_result_cols++] = &str_reason_col;
01329         result_cols[r_local_cseq_col=n_result_cols++] = &str_local_cseq_col;
01330         result_cols[r_version_col=n_result_cols++] = &str_version_col;
01331         result_cols[r_expires_col=n_result_cols++] = &str_expires_col;
01332         result_cols[r_event_col=n_result_cols++] = &str_event_col;
01333         result_cols[r_pres_uri_col=n_result_cols++] = &str_presentity_uri_col;
01334         result_cols[r_contact_col=n_result_cols++] = &str_contact_col;
01335 
01336         /* these ones are unused for some reason !!! */
01337         result_cols[r_remote_cseq_col=n_result_cols++] = &str_remote_cseq_col;
01338         result_cols[r_status_col=n_result_cols++] = &str_status_col;
01339         /*********************************************/
01340 
01341         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, 
01342                                 n_query_cols, n_result_cols, 0, &result )< 0)
01343         {
01344                 LM_ERR("Can't query db\n");
01345                 if(result) pa_dbf.free_result(pa_db, result);
01346                 return(-1);
01347         }
01348 
01349         if(result == NULL) return(-1);
01350 
01351         nr_rows = RES_ROW_N(result);
01352 
01353         LM_DBG("found %d matching dialogs\n", nr_rows);
01354 
01355         /* get the results and fill in return data structure */
01356         for (loop=0; loop <nr_rows; loop++)
01357         {
01358                 rows = RES_ROWS(result);
01359                 row_vals = ROW_VALUES(rows);    
01360 
01361                 memset(&s, 0, sizeof(subs_t));
01362                 s.status= subs->status;
01363 
01364                 s.reason.s= subs->reason.s;
01365                 s.reason.len= s.reason.s?strlen(s.reason.s):0;  //>>>>>>>>>>
01366 
01367                 s.pres_uri.s= (char*)row_vals[r_pres_uri_col].val.string_val;
01368                 s.pres_uri.len= s.pres_uri.s?strlen(s.pres_uri.s):0;
01369 
01370                 s.to_user.s= (char*)row_vals[r_to_user_col].val.string_val;
01371                 s.to_user.len= s.to_user.s?strlen(s.to_user.s):0;
01372 
01373                 s.to_domain.s= (char*)row_vals[r_to_domain_col].val.string_val;
01374                 s.to_domain.len= s.to_domain.s?strlen(s.to_domain.s):0;
01375                 
01376                 s.from_user.s= (char*)row_vals[r_from_user_col].val.string_val;
01377                 s.from_user.len= s.from_user.s?strlen(s.from_user.s):0;
01378                 
01379                 s.from_domain.s= (char*)row_vals[r_from_domain_col].val.string_val;
01380                 s.from_domain.len= s.from_domain.s?strlen(s.from_domain.s):0;
01381                 
01382                 s.watcher_user.s= (char*)row_vals[r_watcher_user_col].val.string_val;
01383                 s.watcher_user.len= s.watcher_user.s?strlen(s.watcher_user.s):0;
01384                 
01385                 s.watcher_domain.s= (char*)row_vals[r_watcher_domain_col].val.string_val;
01386                 s.watcher_domain.len= s.watcher_domain.s?strlen(s.watcher_domain.s):0;
01387 
01388                 s.event_id.s=(char*)row_vals[r_event_id_col].val.string_val;
01389                 s.event_id.len= (s.event_id.s)?strlen(s.event_id.s):0;
01390         
01391                 s.to_tag.s= (char*)row_vals[r_to_tag_col].val.string_val;
01392                 s.to_tag.len= s.to_tag.s?strlen(s.to_tag.s):0;
01393                 
01394                 s.from_tag.s= (char*)row_vals[r_from_tag_col].val.string_val; 
01395                 s.from_tag.len= s.from_tag.s?strlen(s.from_tag.s):0;
01396                 
01397                 s.callid.s= (char*)row_vals[r_callid_col].val.string_val;
01398                 s.callid.len= s.callid.s?strlen(s.callid.s):0;
01399                 
01400                 s.record_route.s=  (char*)row_vals[r_record_route_col].val.string_val;
01401                 s.record_route.len= (s.record_route.s)?strlen(s.record_route.s):0;
01402 
01403                 s.contact.s= (char*)row_vals[r_contact_col].val.string_val;
01404                 s.contact.len= s.contact.s?strlen(s.contact.s):0;
01405                 
01406                 s.sockinfo_str.s = (char*)row_vals[r_sockinfo_col].val.string_val;
01407                 s.sockinfo_str.len = s.sockinfo_str.s?strlen(s.sockinfo_str.s):0;
01408 
01409                 s.local_contact.s = (char*)row_vals[r_local_contact_col].val.string_val;
01410                 s.local_contact.len = s.local_contact.s?strlen(s.local_contact.s):0;
01411 
01412                 ev_sname.s= (char*)row_vals[r_event_col].val.string_val;
01413                 ev_sname.len= ev_sname.s?strlen(ev_sname.s):0;
01414                 
01415                 s.event = contains_event(&ev_sname, NULL);
01416 
01417                 if(s.event == NULL)
01418                 {
01419                         LM_ERR("event not found and set to NULL\n");
01420                 }
01421                 
01422                 s.local_cseq = row_vals[r_local_cseq_col].val.int_val;
01423 
01424                 s.expires = row_vals[r_expires_col].val.int_val;
01425 
01426                 if( s.expires < (int)time(NULL) )
01427                     s.expires = 0;
01428                 else
01429                     s.expires -= (int)time(NULL);
01430 
01431                 s.version = row_vals[r_version_col].val.int_val;
01432 
01433                 cs = mem_copy_subs(&s, PKG_MEM_TYPE);
01434                 if (cs == NULL)
01435                 {
01436                         LM_ERR("while copying subs_t structure\n");
01437                         /* tidy up and return */
01438                         pa_dbf.free_result(pa_db, result);
01439                         return(-1);
01440                 }
01441                 cs->local_cseq++;
01442                 cs->next= (*subs_array);
01443                 (*subs_array)= cs;
01444 
01445                 printf_subs(cs);
01446         }
01447 
01448         pa_dbf.free_result(pa_db, result);
01449 
01450         if (pres_notifier_processes == 0 && subs->status == TERMINATED_STATUS)
01451         {
01452                 /* delete the records */
01453                 if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)< 0)
01454                 {
01455                         LM_ERR("sql delete failed\n");
01456                         return(-1);
01457                 }
01458 
01459                 return(0);
01460         }
01461 
01462         /* otherwise we update the records */
01463         db_cols[n_update_cols] = &str_status_col; 
01464         db_vals[n_update_cols].type = DB1_INT;
01465         db_vals[n_update_cols].nul = 0; 
01466         db_vals[n_update_cols].val.int_val = subs->status;
01467         n_update_cols++;
01468  
01469         db_cols[n_update_cols] = &str_reason_col; 
01470         db_vals[n_update_cols].type = DB1_STR;
01471         db_vals[n_update_cols].nul = 0; 
01472         db_vals[n_update_cols].val.str_val= subs->reason;
01473         n_update_cols++;
01474 
01475         db_cols[n_update_cols] = &str_updated_col; 
01476         db_vals[n_update_cols].type = DB1_INT;
01477         db_vals[n_update_cols].nul = 0; 
01478         db_vals[n_update_cols].val.int_val = 
01479                 core_hash(&subs->callid, &subs->from_tag,
01480                           (pres_waitn_time * pres_notifier_poll_rate
01481                                         * pres_notifier_processes) - 1);
01482         n_update_cols++;
01483 
01484 
01485         if(pa_dbf.update(pa_db, query_cols, 0, query_vals,
01486                                 db_cols,db_vals,n_query_cols,n_update_cols) < 0)
01487         {
01488                 LM_ERR("DB update failed\n");
01489                 return(-1);
01490         }
01491 
01492         return(0);
01493 }
01494 
01495 /********************************************************************************/
01496 
01497 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array)
01498 {
01499         subs_t* s, *ps, *cs;
01500         int i= 0;
01501 
01502         LM_DBG("start\n");
01503 
01504         if (subs_dbmode == DB_ONLY) return(update_pw_dialogs_dbonlymode(subs, subs_array));
01505 
01506         lock_get(&subs_htable[hash_code].lock);
01507         
01508         ps= subs_htable[hash_code].entries;
01509         
01510         while(ps && ps->next)
01511         {
01512                 s= ps->next;
01513 
01514                 if(s->event== subs->event && s->pres_uri.len== subs->pres_uri.len &&
01515                         s->watcher_user.len== subs->watcher_user.len && 
01516                         s->watcher_domain.len==subs->watcher_domain.len &&
01517                         strncmp(s->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len)== 0 &&
01518                         strncmp(s->watcher_user.s, subs->watcher_user.s, s->watcher_user.len)== 0 &&
01519                         strncmp(s->watcher_domain.s,subs->watcher_domain.s,s->watcher_domain.len)==0)
01520                 {
01521                         i++;
01522                         s->status= subs->status;
01523                         s->reason= subs->reason;
01524                         s->db_flag= UPDATEDB_FLAG;
01525 
01526                         cs= mem_copy_subs(s, PKG_MEM_TYPE);
01527                         if(cs== NULL)
01528                         {
01529                                 LM_ERR( "copying subs_t stucture\n");
01530                                 lock_release(&subs_htable[hash_code].lock);
01531                                 return -1;
01532                         }
01533                         cs->local_cseq++;
01534                         cs->expires-= (int)time(NULL);
01535                         cs->next= (*subs_array);
01536                         (*subs_array)= cs;
01537                         if(subs->status== TERMINATED_STATUS)
01538                         {
01539                                 ps->next= s->next;
01540                                 shm_free(s->contact.s);
01541                                 shm_free(s);
01542                                 LM_DBG(" deleted terminated dialog from hash table\n");
01543                         }
01544                         else
01545                                 ps= s;
01546 
01547                         printf_subs(cs);
01548                 }
01549                 else
01550                         ps= s;
01551         }
01552         
01553         LM_DBG("found %d matching dialogs\n", i);
01554         lock_release(&subs_htable[hash_code].lock);
01555         
01556         return 0;
01557 }
01558 
01559 static int w_pres_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2)
01560 {
01561     pv_spec_t *sp;
01562     pv_value_t pv_val;
01563     str watcher_uri, presentity_uri;
01564 
01565     sp = (pv_spec_t *)_sp1;
01566 
01567     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
01568         if (pv_val.flags & PV_VAL_STR) {
01569             watcher_uri = pv_val.rs;
01570             if (watcher_uri.len == 0 || watcher_uri.s == NULL) {
01571                 LM_ERR("missing watcher uri\n");
01572                 return -1;
01573             }
01574         } else {
01575             LM_ERR("watcher pseudo variable value is not string\n");
01576             return -1;
01577         }
01578     } else {
01579         LM_ERR("cannot get watcher pseudo variable value\n");
01580         return -1;
01581     }
01582 
01583     sp = (pv_spec_t *)_sp2;
01584 
01585     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
01586         if (pv_val.flags & PV_VAL_STR) {
01587             presentity_uri = pv_val.rs;
01588             if (presentity_uri.len == 0 || presentity_uri.s == NULL) {
01589                 LM_DBG("missing presentity uri\n");
01590                 return -1;
01591             }
01592         } else {
01593             LM_ERR("presentity pseudo variable value is not string\n");
01594             return -1;
01595         }
01596     } else {
01597         LM_ERR("cannot get presentity pseudo variable value\n");
01598         return -1;
01599     }
01600 
01601     return pres_auth_status(_msg, watcher_uri, presentity_uri);
01602 }
01603 
01604 
01605 int pres_auth_status(struct sip_msg* msg, str watcher_uri, str presentity_uri)
01606 {
01607     str event;
01608     struct sip_uri uri;
01609     pres_ev_t* ev;
01610     str* rules_doc = NULL;
01611     subs_t subs;
01612     int res;
01613 
01614     event.s = "presence";
01615     event.len = 8;
01616 
01617     ev = contains_event(&event, NULL);
01618     if (ev == NULL) {
01619         LM_ERR("event is not registered\n");
01620         return -1;
01621     }
01622     if (ev->get_rules_doc == NULL) {
01623         LM_DBG("event does not require authorization");
01624         return ACTIVE_STATUS;
01625     }
01626     if (parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
01627         LM_ERR("failed to parse presentity uri\n");
01628         return -1;
01629     }
01630     res = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
01631     if ((res < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
01632         LM_DBG( "no xcap rules doc found for presentity uri\n");
01633         return PENDING_STATUS;
01634     }
01635 
01636     if (parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
01637         LM_ERR("failed to parse watcher uri\n");
01638         goto err;
01639     }
01640 
01641     subs.watcher_user = uri.user;
01642     subs.watcher_domain = uri.host;
01643     subs.pres_uri = presentity_uri;
01644     subs.auth_rules_doc = rules_doc;
01645     if (ev->get_auth_status(&subs) < 0) {
01646         LM_ERR( "getting status from rules document\n");
01647         goto err;
01648     }
01649     LM_DBG("auth status of watcher <%.*s> on presentity <%.*s> is %d\n",
01650            watcher_uri.len, watcher_uri.s, presentity_uri.len, presentity_uri.s,
01651            subs.status);
01652     pkg_free(rules_doc->s);
01653     pkg_free(rules_doc);
01654     if ((subs.reason.len == 12) && (strncmp(subs.reason.s, "polite-block", 12) == 0))
01655                 return POLITE_BLOCK_STATUS;
01656     return subs.status;
01657 
01658  err:
01659     pkg_free(rules_doc->s);
01660     pkg_free(rules_doc);
01661     return -1;
01662 }
01663 
01667 static int w_pres_refresh_watchers(struct sip_msg *msg, char *puri,
01668                 char *pevent, char *ptype)
01669 {
01670         str pres_uri;
01671         str event;
01672         int refresh_type;
01673 
01674         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri)!=0)
01675         {
01676                 LM_ERR("invalid uri parameter");
01677                 return -1;
01678         }
01679 
01680         if(fixup_get_svalue(msg, (gparam_p)pevent, &event)!=0)
01681         {
01682                 LM_ERR("invalid uri parameter");
01683                 return -1;
01684         }
01685 
01686         if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type)!=0)
01687         {
01688                 LM_ERR("no type value\n");
01689                 return -1;
01690         }
01691 
01692         if(pres_refresh_watchers(&pres_uri, &event, refresh_type)<0)
01693                 return -1;
01694 
01695         return 1;
01696 }
01697 
01701 static int fixup_refresh_watchers(void** param, int param_no)
01702 {
01703         if(param_no==1)
01704         {
01705                 return fixup_spve_null(param, 1);
01706         } else if(param_no==2) {
01707                 return fixup_spve_null(param, 1);
01708         } else if(param_no==3) {
01709                 return fixup_igp_null(param, 1);
01710         }
01711         return 0;
01712 }
01713 
01714 
01718 static int w_pres_update_watchers(struct sip_msg *msg, char *puri,
01719                 char *pevent)
01720 {
01721         str pres_uri;
01722         str event;
01723         pres_ev_t* ev;
01724         struct sip_uri uri;
01725         str* rules_doc = NULL;
01726         int ret;
01727 
01728         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri)!=0)
01729         {
01730                 LM_ERR("invalid uri parameter");
01731                 return -1;
01732         }
01733 
01734         if(fixup_get_svalue(msg, (gparam_p)pevent, &event)!=0)
01735         {
01736                 LM_ERR("invalid uri parameter");
01737                 return -1;
01738         }
01739 
01740         ev = contains_event(&event, NULL);
01741         if(ev==NULL)
01742         {
01743                 LM_ERR("event %.*s is not registered\n",
01744                                 event.len, event.s);
01745                 return -1;
01746         }
01747         if(ev->get_rules_doc==NULL)
01748         {
01749                 LM_DBG("event  %.*s does not provide rules doc API\n",
01750                                 event.len, event.s);
01751                 return -1;
01752         }
01753         if(parse_uri(pres_uri.s, pres_uri.len, &uri)<0)
01754         {
01755                 LM_ERR("failed to parse presentity uri [%.*s]\n",
01756                                 pres_uri.len, pres_uri.s);
01757                 return -1;
01758         }
01759         ret = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
01760         if((ret < 0) || (rules_doc==NULL) || (rules_doc->s==NULL))
01761         {
01762                 LM_DBG("no xcap rules doc found for presentity uri [%.*s]\n",
01763                                 pres_uri.len, pres_uri.s);
01764                 if(rules_doc != NULL)
01765                         pkg_free(rules_doc);
01766                 return -1;
01767         }
01768         ret = 1;
01769         if(update_watchers_status(pres_uri, ev, rules_doc)<0)
01770         {
01771                 LM_ERR("updating watchers in presence\n");
01772                 ret = -1;
01773         }
01774 
01775         pkg_free(rules_doc->s);
01776         pkg_free(rules_doc);
01777 
01778         return ret;
01779 }
01780 
01784 static int fixup_update_watchers(void** param, int param_no)
01785 {
01786         if(param_no==1)
01787         {
01788                 return fixup_spve_null(param, 1);
01789         } else if(param_no==2) {
01790                 return fixup_spve_null(param, 1);
01791         }
01792         return 0;
01793 }
01794 
01798 static int fixup_update_presentity(void** param, int param_no)
01799 {
01800         if(param_no==1 || param_no==2 || param_no==3)
01801                 return fixup_spve_null(param, 1);
01802 
01803         return 0;
01804 }