presence.c

Go to the documentation of this file.
00001 /*
00002  * $Id: presence.c 5334 2008-12-13 11:05:16Z klaus_darilion $
00003  *
00004  * presence module - presence server implementation
00005  *
00006  * Copyright (C) 2006 Voice Sistem S.R.L.
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2006-08-15  initial version (anca)
00027  */
00028 
00029 /*! \defgroup presence Presence :: A generic implementation of the SIP event package (PUBLISH, SUBSCRIBE, NOTIFY)
00030  *
00031  *    The Kamailio presence module is a generic module for SIP event packages, which is much more than presence.
00032  *    It is extensible by developing other modules that use the internal developer API.
00033  *    Examples:
00034  *    - \ref presence_mwi
00035  *    - \ref presence_xml
00036  */
00037 
00038 /*! \file
00039  * \brief Kamailio presence module
00040  * 
00041  * \ingroup presence 
00042  */
00043 
00044 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <stdlib.h>
00048 #include <sys/types.h>
00049 #include <sys/ipc.h>
00050 #include <unistd.h>
00051 #include <fcntl.h>
00052 #include <time.h>
00053 
00054 #include "../../db/db.h"
00055 #include "../../sr_module.h"
00056 #include "../../dprint.h"
00057 #include "../../error.h"
00058 #include "../../ut.h"
00059 #include "../../parser/parse_to.h"
00060 #include "../../parser/parse_uri.h" 
00061 #include "../../parser/parse_content.h"
00062 #include "../../parser/parse_from.h"
00063 #include "../../mem/mem.h"
00064 #include "../../mem/shm_mem.h"
00065 #include "../../usr_avp.h"
00066 #include "../tm/tm_load.h"
00067 #include "../sl/sl_api.h"
00068 #include "../../pt.h"
00069 #include "../../mi/mi.h"
00070 #include "../pua/hash.h"
00071 #include "publish.h"
00072 #include "subscribe.h"
00073 #include "event_list.h"
00074 #include "bind_presence.h"
00075 #include "notify.h"
00076 
00077 MODULE_VERSION
00078 
00079 #define S_TABLE_VERSION  3
00080 #define P_TABLE_VERSION  3
00081 #define ACTWATCH_TABLE_VERSION 9
00082 
00083 char *log_buf = NULL;
00084 static int clean_period=100;
00085 static int db_update_period=100;
00086 
00087 /* database connection */
00088 db_con_t *pa_db = NULL;
00089 db_func_t pa_dbf;
00090 str presentity_table= str_init("presentity");
00091 str active_watchers_table = str_init("active_watchers");
00092 str watchers_table= str_init("watchers");
00093 
00094 int library_mode= 0;
00095 str server_address= {0, 0};
00096 evlist_t* EvList= NULL;
00097 
00098 /* to tag prefix */
00099 char* to_tag_pref = "10";
00100 
00101 /* TM bind */
00102 struct tm_binds tmb;
00103 /* SL bind */
00104 struct sl_binds slb;
00105 
00106 /** module functions */
00107 
00108 static int mod_init(void);
00109 static int child_init(int);
00110 static void destroy(void);
00111 int stored_pres_info(struct sip_msg* msg, char* pres_uri, char* s);
00112 static int fixup_presence(void** param, int param_no);
00113 static int fixup_subscribe(void** param, int param_no);
00114 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param);
00115 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param);
00116 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array);
00117 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc);
00118 static int mi_child_init(void);
00119 
00120 int counter =0;
00121 int pid = 0;
00122 char prefix='a';
00123 int startup_time=0;
00124 str db_url = {0, 0};
00125 int expires_offset = 0;
00126 int max_expires= 3600;
00127 int shtable_size= 9;
00128 shtable_t subs_htable= NULL;
00129 int fallback2db= 0;
00130 int sphere_enable= 0;
00131 
00132 int phtable_size= 9;
00133 phtable_t* pres_htable;
00134 
00135 static cmd_export_t cmds[]=
00136 {
00137    {"handle_publish",  (cmd_function)handle_publish,  0,fixup_presence,0, REQUEST_ROUTE},
00138    {"handle_publish",  (cmd_function)handle_publish,  1,fixup_presence, 0, REQUEST_ROUTE},
00139    {"handle_subscribe",(cmd_function)handle_subscribe,0,fixup_subscribe,0, REQUEST_ROUTE},
00140    {"bind_presence",   (cmd_function)bind_presence,   1,     0,         0,  0},
00141    { 0,                    0,                         0,     0,         0,  0}
00142 };
00143 
00144 static param_export_t params[]={
00145    { "db_url",                 STR_PARAM, &db_url.s},
00146    { "presentity_table",       STR_PARAM, &presentity_table.s},
00147    { "active_watchers_table",  STR_PARAM, &active_watchers_table.s},
00148    { "watchers_table",         STR_PARAM, &watchers_table.s},
00149    { "clean_period",           INT_PARAM, &clean_period },
00150    { "db_update_period",       INT_PARAM, &db_update_period },
00151    { "to_tag_pref",            STR_PARAM, &to_tag_pref },
00152    { "expires_offset",         INT_PARAM, &expires_offset },
00153    { "max_expires",            INT_PARAM, &max_expires },
00154    { "server_address",         STR_PARAM, &server_address.s},
00155    { "subs_htable_size",       INT_PARAM, &shtable_size},
00156    { "pres_htable_size",       INT_PARAM, &phtable_size},
00157    { "fallback2db",            INT_PARAM, &fallback2db},
00158    { "enable_sphere_check",    INT_PARAM, &sphere_enable},
00159     {0,0,0}
00160 };
00161 
00162 static mi_export_t mi_cmds[] = {
00163    { "refreshWatchers", mi_refreshWatchers,    0,  0,  mi_child_init},
00164    { "cleanup",         mi_cleanup,            0,  0,  mi_child_init},
00165    {  0,                0,                     0,  0,  0}
00166 };
00167 
00168 /** module exports */
00169 struct module_exports exports= {
00170    "presence",       /* module name */
00171    DEFAULT_DLFLAGS,  /* dlopen flags */
00172    cmds,          /* exported functions */
00173    params,           /* exported parameters */
00174    0,             /* exported statistics */
00175    mi_cmds,          /* exported MI functions */
00176    0,             /* exported pseudo-variables */
00177    0,             /* extra processes */
00178    mod_init,         /* module initialization function */
00179    0,             /* response handling function */
00180    (destroy_function) destroy,   /* destroy function */
00181    child_init                    /* per-child init function */
00182 };
00183 
00184 /**
00185  * init module function
00186  */
00187 static int mod_init(void)
00188 {
00189    db_url.len = db_url.s ? strlen(db_url.s) : 0;
00190    LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
00191    presentity_table.len = strlen(presentity_table.s);
00192    active_watchers_table.len = strlen(active_watchers_table.s);
00193    watchers_table.len = strlen(watchers_table.s);
00194 
00195    if(db_url.s== NULL)
00196       library_mode= 1;
00197 
00198    if(library_mode== 1)
00199    {
00200       LM_DBG("Presence module used for API library purpose only\n");
00201       EvList= init_evlist();
00202       if(!EvList)
00203       {
00204          LM_ERR("unsuccessful initialize event list\n");
00205          return -1;
00206       }
00207       return 0;
00208    }
00209 
00210    if(expires_offset<0)
00211       expires_offset = 0;
00212    
00213    if(to_tag_pref==NULL || strlen(to_tag_pref)==0)
00214       to_tag_pref="10";
00215 
00216    if(max_expires<= 0)
00217       max_expires = 3600;
00218 
00219    if(server_address.s== NULL)
00220       LM_DBG("server_address parameter not set in configuration file\n");
00221    
00222    if(server_address.s)
00223       server_address.len= strlen(server_address.s);
00224    else
00225       server_address.len= 0;
00226 
00227    /* load SL API */
00228    if(load_sl_api(&slb)==-1)
00229    {
00230       LM_ERR("Can't load sl functions. Module SL not loaded?\n");
00231       return -1;
00232    }
00233 
00234    /* load all TM stuff */
00235    if(load_tm_api(&tmb)==-1)
00236    {
00237       LM_ERR("Can't load tm functions. Module TM not loaded?\n");
00238       return -1;
00239    }
00240    
00241    if(db_url.s== NULL)
00242    {
00243       LM_ERR("database url not set!\n");
00244       return -1;
00245    }
00246 
00247    /* binding to database module  */
00248    if (db_bind_mod(&db_url, &pa_dbf))
00249    {
00250       LM_ERR("Database module not found\n");
00251       return -1;
00252    }
00253    
00254 
00255    if (!DB_CAPABILITY(pa_dbf, DB_CAP_ALL))
00256    {
00257       LM_ERR("Database module does not implement all functions"
00258             " needed by presence module\n");
00259       return -1;
00260    }
00261 
00262    pa_db = pa_dbf.init(&db_url);
00263    if (!pa_db)
00264    {
00265       LM_ERR("Connection to database failed\n");
00266       return -1;
00267    }
00268    
00269    /*verify table versions */
00270    if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) ||
00271       (db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) ||
00272       (db_check_table_version(&pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION) < 0)) {
00273          LM_ERR("error during table version check\n");
00274          return -1;
00275    }
00276 
00277    EvList= init_evlist();
00278    if(!EvList)
00279    {
00280       LM_ERR("initializing event list\n");
00281       return -1;
00282    }
00283 
00284    if(shtable_size< 1)
00285       shtable_size= 512;
00286    else
00287       shtable_size= 1<< shtable_size;
00288 
00289    subs_htable= new_shtable(shtable_size);
00290    if(subs_htable== NULL)
00291    {
00292       LM_ERR(" initializing subscribe hash table\n");
00293       return -1;
00294    }
00295 
00296    if(restore_db_subs()< 0)
00297    {
00298       LM_ERR("restoring subscribe info from database\n");
00299       return -1;
00300    }
00301 
00302    if(phtable_size< 1)
00303       phtable_size= 256;
00304    else
00305       phtable_size= 1<< phtable_size;
00306 
00307    pres_htable= new_phtable();
00308    if(pres_htable== NULL)
00309    {
00310       LM_ERR("initializing presentity hash table\n");
00311       return -1;
00312    }
00313 
00314    if(pres_htable_restore()< 0)
00315    {
00316       LM_ERR("filling in presentity hash table from database\n");
00317       return -1;
00318    }
00319 
00320    startup_time = (int) time(NULL);
00321    
00322    if(clean_period>0)
00323    {
00324       register_timer(msg_presentity_clean, 0, clean_period);
00325       register_timer(msg_watchers_clean, 0, clean_period);
00326    }
00327    
00328    if(db_update_period>0)
00329       register_timer(timer_db_update, 0, db_update_period);
00330 
00331    if(pa_db)
00332       pa_dbf.close(pa_db);
00333    pa_db = NULL;
00334 
00335    return 0;
00336 }
00337 
00338 /**
00339  * Initialize children
00340  */
00341 static int child_init(int rank)
00342 {
00343    pid = my_pid();
00344    
00345    if(library_mode)
00346       return 0;
00347 
00348    if (pa_dbf.init==0)
00349    {
00350       LM_CRIT("child_init: database not bound\n");
00351       return -1;
00352    }
00353    pa_db = pa_dbf.init(&db_url);
00354    if (!pa_db)
00355    {
00356       LM_ERR("child %d: unsuccessful connecting to database\n", rank);
00357       return -1;
00358    }
00359    
00360    if (pa_dbf.use_table(pa_db, &presentity_table) < 0)  
00361    {
00362       LM_ERR( "child %d:unsuccessful use_table presentity_table\n", rank);
00363       return -1;
00364    }
00365 
00366    if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)  
00367    {
00368       LM_ERR( "child %d:unsuccessful use_table active_watchers_table\n",
00369             rank);
00370       return -1;
00371    }
00372 
00373    if (pa_dbf.use_table(pa_db, &watchers_table) < 0)  
00374    {
00375       LM_ERR( "child %d:unsuccessful use_table watchers_table\n", rank);
00376       return -1;
00377    }
00378 
00379    LM_DBG("child %d: Database connection opened successfully\n", rank);
00380    
00381    return 0;
00382 }
00383 
00384 static int mi_child_init(void)
00385 {
00386    if(library_mode)
00387       return 0;
00388 
00389    if (pa_dbf.init==0)
00390    {
00391       LM_CRIT("database not bound\n");
00392       return -1;
00393    }
00394    pa_db = pa_dbf.init(&db_url);
00395    if (!pa_db)
00396    {
00397       LM_ERR("connecting database\n");
00398       return -1;
00399    }
00400    
00401    if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
00402    {
00403       LM_ERR( "unsuccessful use_table presentity_table\n");
00404       return -1;
00405    }
00406 
00407    if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
00408    {
00409       LM_ERR( "unsuccessful use_table active_watchers_table\n");
00410       return -1;
00411    }
00412 
00413    if (pa_dbf.use_table(pa_db, &watchers_table) < 0)
00414    {
00415       LM_ERR( "unsuccessful use_table watchers_table\n");
00416       return -1;
00417    }
00418 
00419    LM_DBG("Database connection opened successfully\n");
00420    return 0;
00421 }
00422 
00423 
00424 /*
00425  * destroy function
00426  */
00427 static void destroy(void)
00428 {
00429    if(subs_htable && pa_db)
00430       timer_db_update(0, 0);
00431 
00432    if(subs_htable)
00433       destroy_shtable(subs_htable, shtable_size);
00434    
00435    if(pres_htable)
00436       destroy_phtable();
00437 
00438    if(pa_db && pa_dbf.close)
00439       pa_dbf.close(pa_db);
00440    
00441    destroy_evlist();
00442 }
00443 
00444 static int fixup_presence(void** param, int param_no)
00445 {
00446    pv_elem_t *model;
00447    str s;
00448 
00449    if(library_mode)
00450    {
00451       LM_ERR("Bad config - you can not call 'handle_publish' function"
00452             " (db_url not set)\n");
00453       return -1;
00454    }
00455    if(param_no== 0)
00456       return 0;
00457 
00458    if(*param)
00459    {
00460       s.s = (char*)(*param); s.len = strlen(s.s);
00461       if(pv_parse_format(&s, &model)<0)
00462       {
00463          LM_ERR( "wrong format[%s]\n",(char*)(*param));
00464          return E_UNSPEC;
00465       }
00466  
00467       *param = (void*)model;
00468       return 0;
00469    }
00470    LM_ERR( "null format\n");
00471    return E_UNSPEC;
00472 }
00473 
00474 static int fixup_subscribe(void** param, int param_no)
00475 {
00476 
00477    if(library_mode)
00478    {
00479       LM_ERR("Bad config - you can not call 'handle_subscribe' function"
00480             " (db_url not set)\n");
00481       return -1;
00482    }
00483    return 0;
00484 }
00485 
00486 /*! \brief
00487  *  mi cmd: refreshWatchers
00488  *       <presentity_uri> 
00489  *       <event>
00490  *          <refresh_type> // can be:  = 0 -> watchers autentification type or
00491  *                           != 0 -> publish type //        
00492  *    * */
00493 
00494 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param)
00495 {
00496    struct mi_node* node= NULL;
00497    str pres_uri, event;
00498    struct sip_uri uri;
00499    pres_ev_t* ev;
00500    str* rules_doc= NULL;
00501    int result;
00502    unsigned int refresh_type;
00503 
00504    LM_DBG("start\n");
00505    
00506    node = cmd->node.kids;
00507    if(node == NULL)
00508       return 0;
00509 
00510    /* Get presentity URI */
00511    pres_uri = node->value;
00512    if(pres_uri.s == NULL || pres_uri.len== 0)
00513    {
00514       LM_ERR( "empty uri\n");
00515       return init_mi_tree(404, "Empty presentity URI", 20);
00516    }
00517    
00518    node = node->next;
00519    if(node == NULL)
00520       return 0;
00521    event= node->value;
00522    if(event.s== NULL || event.len== 0)
00523    {
00524       LM_ERR( "empty event parameter\n");
00525       return init_mi_tree(400, "Empty event parameter", 21);
00526    }
00527    LM_DBG("event '%.*s'\n",  event.len, event.s);
00528    
00529    node = node->next;
00530    if(node == NULL)
00531       return 0;
00532    if(node->value.s== NULL || node->value.len== 0)
00533    {
00534       LM_ERR( "empty event parameter\n");
00535       return init_mi_tree(400, "Empty event parameter", 21);      
00536    }
00537    if(str2int(&node->value, &refresh_type)< 0)
00538    {
00539       LM_ERR("converting string to int\n");
00540       goto error;
00541    }
00542 
00543    if(node->next!= NULL)
00544    {
00545       LM_ERR( "Too many parameters\n");
00546       return init_mi_tree(400, "Too many parameters", 19);
00547    }
00548 
00549    ev= contains_event(&event, NULL);
00550    if(ev== NULL)
00551    {
00552       LM_ERR( "wrong event parameter\n");
00553       return 0;
00554    }
00555    
00556    if(refresh_type== 0) /* if a request to refresh watchers authorization*/
00557    {
00558       if(ev->get_rules_doc== NULL)
00559       {
00560          LM_ERR("wrong request for a refresh watchers authorization status"
00561                "for an event that does not require authorization\n");
00562          goto error;
00563       }
00564       
00565       if(parse_uri(pres_uri.s, pres_uri.len, &uri)< 0)
00566       {
00567          LM_ERR( "parsing uri\n");
00568          goto error;
00569       }
00570 
00571       result= ev->get_rules_doc(&uri.user,&uri.host,&rules_doc);
00572       if(result< 0 || rules_doc==NULL || rules_doc->s== NULL)
00573       {
00574          LM_ERR( "no rules doc found for the user\n");
00575          goto error;
00576       }
00577    
00578       if(update_watchers_status(pres_uri, ev, rules_doc)< 0)
00579       {
00580          LM_ERR("failed to update watchers\n");
00581          goto error;
00582       }
00583 
00584       pkg_free(rules_doc->s);
00585       pkg_free(rules_doc);
00586       rules_doc = NULL;
00587 
00588    }
00589    else     /* if a request to refresh Notified info */
00590    {
00591       if(query_db_notify(&pres_uri, ev, NULL)< 0)
00592       {
00593          LM_ERR("sending Notify requests\n");
00594          goto error;
00595       }
00596 
00597    }
00598       
00599    return init_mi_tree(200, "OK", 2);
00600 
00601 error:
00602    if(rules_doc)
00603    {
00604       if(rules_doc->s)
00605          pkg_free(rules_doc->s);
00606       pkg_free(rules_doc);
00607    }
00608    return 0;
00609 }
00610 
00611 /* 
00612  *  mi cmd: cleanup
00613  *    * */
00614 
00615 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param)
00616 {
00617    LM_DBG("mi_cleanup:start\n");
00618    
00619    (void)msg_watchers_clean(0,0);
00620    (void)msg_presentity_clean(0,0);
00621       
00622    return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00623 }
00624 
00625 int pres_update_status(subs_t subs, str reason, db_key_t* query_cols,
00626         db_val_t* query_vals, int n_query_cols, subs_t** subs_array)
00627 {
00628    db_key_t update_cols[5];
00629    db_val_t update_vals[5];
00630    int n_update_cols= 0;
00631    int u_status_col, u_reason_col, q_wuser_col, q_wdomain_col;
00632    int status;
00633    query_cols[q_wuser_col=n_query_cols]= &str_watcher_username_col;
00634    query_vals[n_query_cols].nul= 0;
00635    query_vals[n_query_cols].type= DB_STR;
00636    n_query_cols++;
00637 
00638    query_cols[q_wdomain_col=n_query_cols]= &str_watcher_domain_col;
00639    query_vals[n_query_cols].nul= 0;
00640    query_vals[n_query_cols].type= DB_STR;
00641    n_query_cols++;
00642 
00643    update_cols[u_status_col= n_update_cols]= &str_status_col;
00644    update_vals[u_status_col].nul= 0;
00645    update_vals[u_status_col].type= DB_INT;
00646    n_update_cols++;
00647 
00648    update_cols[u_reason_col= n_update_cols]= &str_reason_col;
00649    update_vals[u_reason_col].nul= 0;
00650    update_vals[u_reason_col].type= DB_STR;
00651    n_update_cols++;
00652 
00653    status= subs.status;
00654    if(subs.event->get_auth_status(&subs)< 0)
00655    {
00656       LM_ERR( "getting status from rules document\n");
00657       return -1;
00658    }
00659    LM_DBG("subs.status= %d\n", subs.status);
00660    if(get_status_str(subs.status)== NULL)
00661    {
00662       LM_ERR("wrong status: %d\n", subs.status);
00663       return -1;
00664    }
00665 
00666    if(subs.status!= status || reason.len!= subs.reason.len ||
00667       (reason.s && subs.reason.s && strncmp(reason.s, subs.reason.s,
00668                                    reason.len)))
00669    {
00670       /* update in watchers_table */
00671       query_vals[q_wuser_col].val.str_val= subs.from_user; 
00672       query_vals[q_wdomain_col].val.str_val= subs.from_domain; 
00673 
00674       update_vals[u_status_col].val.int_val= subs.status;
00675       update_vals[u_reason_col].val.str_val= subs.reason;
00676       
00677       if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
00678       {
00679          LM_ERR( "in use_table\n");
00680          return -1;
00681       }
00682 
00683       if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
00684                update_vals, n_query_cols, n_update_cols)< 0)
00685       {
00686          LM_ERR( "in sql update\n");
00687          return -1;
00688       }
00689       /* save in the list all affected dialogs */
00690       /* if status switches to terminated -> delete dialog */
00691       if(update_pw_dialogs(&subs, subs.db_flag, subs_array)< 0)
00692       {
00693          LM_ERR( "extracting dialogs from [watcher]=%.*s@%.*s to"
00694             " [presentity]=%.*s\n", subs.from_user.len, subs.from_user.s,
00695             subs.from_domain.len, subs.from_domain.s, subs.pres_uri.len,
00696             subs.pres_uri.s);
00697          return -1;
00698       }
00699    }
00700     return 0;
00701 }
00702 
00703 int pres_db_delete_status(subs_t* s)
00704 {
00705     int n_query_cols= 0;
00706     db_key_t query_cols[5];
00707     db_val_t query_vals[5];
00708 
00709     if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
00710     {
00711         LM_ERR("sql use table failed\n");
00712         return -1;
00713     }
00714 
00715     query_cols[n_query_cols]= &str_event_col;
00716     query_vals[n_query_cols].nul= 0;
00717     query_vals[n_query_cols].type= DB_STR;
00718     query_vals[n_query_cols].val.str_val= s->event->name ;
00719     n_query_cols++;
00720 
00721     query_cols[n_query_cols]= &str_presentity_uri_col;
00722     query_vals[n_query_cols].nul= 0;
00723     query_vals[n_query_cols].type= DB_STR;
00724     query_vals[n_query_cols].val.str_val= s->pres_uri;
00725     n_query_cols++;
00726 
00727     query_cols[n_query_cols]= &str_watcher_username_col;
00728     query_vals[n_query_cols].nul= 0;
00729     query_vals[n_query_cols].type= DB_STR;
00730     query_vals[n_query_cols].val.str_val= s->from_user;
00731     n_query_cols++;
00732 
00733     query_cols[n_query_cols]= &str_watcher_domain_col;
00734     query_vals[n_query_cols].nul= 0;
00735     query_vals[n_query_cols].type= DB_STR;
00736     query_vals[n_query_cols].val.str_val= s->from_domain;
00737     n_query_cols++;
00738 
00739     if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)< 0)
00740     {
00741         LM_ERR("sql delete failed\n");
00742         return -1;
00743     }
00744     return 0;
00745 
00746 }
00747 
00748 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc)
00749 {
00750    subs_t subs;
00751    db_key_t query_cols[6], result_cols[5];
00752    db_val_t query_vals[6];
00753    int n_result_cols= 0, n_query_cols = 0;
00754    db_res_t* result= NULL;
00755    db_row_t *row;
00756    db_val_t *row_vals ;
00757    int i;
00758    str w_user, w_domain, reason= {0, 0};
00759    unsigned int status;
00760    int status_col, w_user_col, w_domain_col, reason_col;
00761    subs_t* subs_array= NULL,* s;
00762    unsigned int hash_code;
00763    int err_ret= -1;
00764    int n= 0;
00765 
00766    typedef struct ws
00767    {
00768       int status;
00769       str reason;
00770       str w_user;
00771       str w_domain;
00772    }ws_t;
00773    ws_t* ws_list= NULL;
00774 
00775     LM_DBG("start\n");
00776 
00777    if(ev->content_type.s== NULL)
00778    {
00779       ev= contains_event(&ev->name, NULL);
00780       if(ev== NULL)
00781       {
00782          LM_ERR("wrong event parameter\n");
00783          return 0;
00784       }
00785    }
00786 
00787    subs.pres_uri= pres_uri;
00788    subs.event= ev;
00789    subs.auth_rules_doc= rules_doc;
00790 
00791    /* update in watchers_table */
00792    query_cols[n_query_cols]= &str_presentity_uri_col;
00793    query_vals[n_query_cols].nul= 0;
00794    query_vals[n_query_cols].type= DB_STR;
00795    query_vals[n_query_cols].val.str_val= pres_uri;
00796    n_query_cols++;
00797 
00798    query_cols[n_query_cols]= &str_event_col;
00799    query_vals[n_query_cols].nul= 0;
00800    query_vals[n_query_cols].type= DB_STR;
00801    query_vals[n_query_cols].val.str_val= ev->name;
00802    n_query_cols++;
00803 
00804    result_cols[status_col= n_result_cols++]= &str_status_col;
00805    result_cols[reason_col= n_result_cols++]= &str_reason_col;
00806    result_cols[w_user_col= n_result_cols++]= &str_watcher_username_col;
00807    result_cols[w_domain_col= n_result_cols++]= &str_watcher_domain_col;
00808 
00809    if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
00810    {
00811       LM_ERR( "in use_table\n");
00812       goto done;
00813    }
00814 
00815    if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,n_query_cols,
00816             n_result_cols, 0, &result)< 0)
00817    {
00818       LM_ERR( "in sql query\n");
00819       goto done;
00820    }
00821    if(result== NULL)
00822       return 0;
00823 
00824    if(result->n<= 0)
00825    {
00826       err_ret= 0;
00827       goto done;
00828    }
00829 
00830     LM_DBG("found %d record-uri in watchers_table\n", result->n);
00831    hash_code= core_hash(&pres_uri, &ev->name, shtable_size);
00832    subs.db_flag= hash_code;
00833 
00834     /*must do a copy as sphere_check requires database queries */
00835    if(sphere_enable)
00836    {
00837         n= result->n;
00838       ws_list= (ws_t*)pkg_malloc(n * sizeof(ws_t));
00839       if(ws_list== NULL)
00840       {
00841          LM_ERR("No more private memory\n");
00842          goto done;
00843       }
00844       memset(ws_list, 0, n * sizeof(ws_t));
00845 
00846       for(i= 0; i< result->n ; i++)
00847       {
00848          row= &result->rows[i];
00849          row_vals = ROW_VALUES(row);
00850 
00851          status= row_vals[status_col].val.int_val;
00852    
00853          reason.s= (char*)row_vals[reason_col].val.string_val;
00854          reason.len= reason.s?strlen(reason.s):0;
00855 
00856          w_user.s= (char*)row_vals[w_user_col].val.string_val;
00857          w_user.len= strlen(w_user.s);
00858 
00859          w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
00860          w_domain.len= strlen(w_domain.s);
00861 
00862          if(reason.len)
00863          {
00864             ws_list[i].reason.s = (char*)pkg_malloc(reason.len* sizeof(char));
00865             if(ws_list[i].reason.s== NULL)
00866             {  
00867                LM_ERR("No more private memory\n");
00868                goto done;
00869             }
00870             memcpy(ws_list[i].reason.s, reason.s, reason.len);
00871             ws_list[i].reason.len= reason.len;
00872          }
00873          else
00874             ws_list[i].reason.s= NULL;
00875             
00876          ws_list[i].w_user.s = (char*)pkg_malloc(w_user.len* sizeof(char));
00877          if(ws_list[i].w_user.s== NULL)
00878          {
00879             LM_ERR("No more private memory\n");
00880             goto done;
00881 
00882          }
00883          memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
00884          ws_list[i].w_user.len= w_user.len;
00885       
00886           ws_list[i].w_domain.s = (char*)pkg_malloc(w_domain.len* sizeof(char));
00887          if(ws_list[i].w_domain.s== NULL)
00888          {
00889             LM_ERR("No more private memory\n");
00890             goto done;
00891          }
00892          memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
00893          ws_list[i].w_domain.len= w_domain.len;
00894          
00895          ws_list[i].status= status;
00896       }
00897 
00898       pa_dbf.free_result(pa_db, result);
00899       result= NULL;
00900 
00901       for(i=0; i< n; i++)
00902       {
00903          subs.from_user = ws_list[i].w_user;
00904          subs.from_domain = ws_list[i].w_domain;
00905          subs.status = ws_list[i].status;
00906          memset(&subs.reason, 0, sizeof(str));
00907 
00908          if( pres_update_status(subs, reason, query_cols, query_vals,
00909                n_query_cols, &subs_array)< 0)
00910          {
00911             LM_ERR("failed to update watcher status\n");
00912             goto done;
00913          }
00914 
00915       }
00916         
00917       for(i=0; i< n; i++)
00918       {
00919          pkg_free(ws_list[i].w_user.s);
00920          pkg_free(ws_list[i].w_domain.s);
00921          if(ws_list[i].reason.s)
00922             pkg_free(ws_list[i].reason.s);
00923       }
00924       ws_list= NULL;
00925 
00926       goto send_notify;
00927 
00928    }
00929    
00930    for(i = 0; i< result->n; i++)
00931    {
00932       row= &result->rows[i];
00933       row_vals = ROW_VALUES(row);
00934 
00935       status= row_vals[status_col].val.int_val;
00936    
00937       reason.s= (char*)row_vals[reason_col].val.string_val;
00938       reason.len= reason.s?strlen(reason.s):0;
00939 
00940       w_user.s= (char*)row_vals[w_user_col].val.string_val;
00941       w_user.len= strlen(w_user.s);
00942 
00943       w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
00944       w_domain.len= strlen(w_domain.s);
00945 
00946       subs.from_user= w_user;
00947       subs.from_domain= w_domain;
00948       subs.status= status;
00949       memset(&subs.reason, 0, sizeof(str));
00950 
00951       if( pres_update_status(subs,reason, query_cols, query_vals,
00952                n_query_cols, &subs_array)< 0)
00953       {
00954          LM_ERR("failed to update watcher status\n");
00955          goto done;
00956       }
00957     }
00958 
00959    pa_dbf.free_result(pa_db, result);
00960    result= NULL;
00961 
00962 send_notify:
00963 
00964    s= subs_array;
00965 
00966    while(s)
00967    {
00968 
00969       if(notify(s, NULL, NULL, 0)< 0)
00970       {
00971          LM_ERR( "sending Notify request\n");
00972          goto done;
00973       }
00974 
00975         /* delete from database also */
00976         if(s->status== TERMINATED_STATUS)
00977         {
00978             if(pres_db_delete_status(s)<0)
00979             {
00980                 err_ret= -1;
00981                 LM_ERR("failed to delete terminated dialog from database\n");
00982                 goto done;
00983             }
00984         }
00985 
00986         s= s->next;
00987    }
00988 
00989    free_subs_list(subs_array, PKG_MEM_TYPE, 0);
00990    return 0;
00991 
00992 done:
00993    if(result)
00994       pa_dbf.free_result(pa_db, result);
00995    free_subs_list(subs_array, PKG_MEM_TYPE, 0);
00996    if(ws_list)
00997    {
00998       for(i= 0; i< n; i++)
00999       {
01000          if(ws_list[i].w_user.s)
01001             pkg_free(ws_list[i].w_user.s);
01002          else
01003             break;
01004          if(ws_list[i].w_domain.s)
01005             pkg_free(ws_list[i].w_domain.s);
01006          if(ws_list[i].reason.s)
01007             pkg_free(ws_list[i].reason.s);
01008       }
01009    }
01010    return err_ret;
01011 }
01012 
01013 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array)
01014 {
01015    subs_t* s, *ps, *cs;
01016    int i= 0;
01017 
01018     LM_DBG("start\n");
01019    lock_get(&subs_htable[hash_code].lock);
01020    
01021     ps= subs_htable[hash_code].entries;
01022    
01023    while(ps && ps->next)
01024    {
01025       s= ps->next;
01026 
01027       if(s->event== subs->event && s->pres_uri.len== subs->pres_uri.len &&
01028          s->from_user.len== subs->from_user.len && 
01029          s->from_domain.len==subs->from_domain.len &&
01030          strncmp(s->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len)== 0 &&
01031          strncmp(s->from_user.s, subs->from_user.s, s->from_user.len)== 0 &&
01032          strncmp(s->from_domain.s,subs->from_domain.s,s->from_domain.len)==0)
01033       {
01034          i++;
01035          s->status= subs->status;
01036          s->reason= subs->reason;
01037          s->db_flag= UPDATEDB_FLAG;
01038 
01039          cs= mem_copy_subs(s, PKG_MEM_TYPE);
01040          if(cs== NULL)
01041          {
01042             LM_ERR( "copying subs_t stucture\n");
01043                 lock_release(&subs_htable[hash_code].lock);
01044                 return -1;
01045          }
01046          cs->expires-= (int)time(NULL);
01047          cs->next= (*subs_array);
01048          (*subs_array)= cs;
01049          if(subs->status== TERMINATED_STATUS)
01050          {
01051             ps->next= s->next;
01052             shm_free(s->contact.s);
01053                 shm_free(s);
01054                 LM_DBG(" deleted terminated dialog from hash table\n");
01055             }
01056          else
01057             ps= s;
01058 
01059          printf_subs(cs);
01060       }
01061       else
01062          ps= s;
01063    }
01064    
01065     LM_DBG("found %d matching dialogs\n", i);
01066     lock_release(&subs_htable[hash_code].lock);
01067    
01068     return 0;
01069 }

Generated on Thu May 24 08:00:52 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6