modules_k/presence/publish.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice Sistem S.R.L.
00003  *
00004  * This file is part of Kamailio, a free SIP server.
00005  *
00006  * Kamailio is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version
00010  *
00011  * Kamailio is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License 
00017  * along with this program; if not, write to the Free Software 
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  * History:
00021  * --------
00022  *  2006-08-15  initial version (Anca Vamanu)
00023  */
00024 
00032 #include <time.h>
00033 
00034 #include "../../ut.h"
00035 #include "../../str.h"
00036 #include "../../mod_fix.h"
00037 #include "../../parser/parse_to.h"
00038 #include "../../parser/parse_uri.h" 
00039 #include "../../parser/parse_expires.h" 
00040 #include "../../parser/parse_event.h" 
00041 #include "../../parser/parse_content.h" 
00042 #include "../../lock_ops.h"
00043 #include "../../hashes.h"
00044 #include "../../lib/kcore/cmpapi.h"
00045 #include "../../lib/srdb1/db.h"
00046 #include "presence.h"
00047 #include "notify.h"
00048 #include "utils_func.h"
00049 #include "publish.h"
00050 #include "presentity.h"
00051 #include "../xcap_client/xcap_callbacks.h"
00052 
00053 extern gen_lock_set_t* set;
00054 
00055 static str pu_400a_rpl = str_init("Bad request");
00056 static str pu_400b_rpl = str_init("Invalid request");
00057 static str pu_500_rpl  = str_init("Server Internal Error");
00058 static str pu_489_rpl  = str_init("Bad Event");
00059 
00060 static str str_doc_uri_col = str_init("doc_uri");
00061 static str str_doc_type_col = str_init("doc_type");
00062 static str str_doc_col = str_init("doc");
00063 
00064 struct p_modif
00065 {
00066         presentity_t* p;
00067         str uri;
00068 };
00069 
00070 void msg_presentity_clean(unsigned int ticks,void *param)
00071 {
00072         db_key_t db_keys[2], result_cols[4];
00073         db_val_t db_vals[2], *values;
00074         db_op_t  db_ops[2] ;
00075         db1_res_t *result = NULL;
00076         db_row_t *rows;
00077         int n_db_cols = 0, n_result_cols = 0;
00078         int event_col, etag_col, user_col, domain_col;
00079         int i = 0, num_watchers = 0;
00080         presentity_t pres;
00081         str uri = {0, 0}, event, *rules_doc = NULL;
00082 
00083         LM_DBG("cleaning expired presentity information\n");
00084         if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
00085         {
00086                 LM_ERR("in use_table\n");
00087                 return ;
00088         }
00089 
00090         db_keys[n_db_cols] = &str_expires_col;
00091         db_ops[n_db_cols] = OP_LT;
00092         db_vals[n_db_cols].type = DB1_INT;
00093         db_vals[n_db_cols].nul = 0;
00094         db_vals[n_db_cols].val.int_val = (int)time(NULL);
00095         n_db_cols++;
00096 
00097         db_keys[n_db_cols] = &str_expires_col;
00098         db_ops[n_db_cols] = OP_GT;
00099         db_vals[n_db_cols].type = DB1_INT;
00100         db_vals[n_db_cols].nul = 0;
00101         db_vals[n_db_cols].val.int_val = 0;
00102         n_db_cols++;
00103 
00104         result_cols[user_col= n_result_cols++] = &str_username_col;
00105         result_cols[domain_col=n_result_cols++] = &str_domain_col;
00106         result_cols[etag_col=n_result_cols++] = &str_etag_col;
00107         result_cols[event_col=n_result_cols++] = &str_event_col;
00108 
00109         static str query_str = str_init("username");
00110         if (db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, db_keys, db_ops,
00111                                 db_vals, result_cols, n_db_cols, n_result_cols,
00112                                 &query_str, &result) < 0)
00113         {
00114                 LM_ERR("failed to query database for expired messages\n");
00115                 goto delete_pres;
00116         }
00117 
00118         if(result == NULL)
00119         {
00120                 LM_ERR("bad result\n");
00121                 return;
00122         }
00123 
00124         LM_DBG("found n= %d expires messages\n ",result->n);
00125 
00126         do {
00127                 rows = RES_ROWS(result);
00128 
00129                 for(i = 0; i < RES_ROW_N(result); i++)
00130                 {
00131                         values = ROW_VALUES(&rows[i]);
00132                         memset(&pres, 0, sizeof(presentity_t));
00133 
00134                         pres.user.s = (char *) VAL_STRING(&values[user_col]);
00135                         pres.user.len = strlen(pres.user.s);
00136                         pres.domain.s = (char *) VAL_STRING(&values[domain_col]);
00137                         pres.domain.len = strlen(pres.domain.s);
00138                         pres.etag.s = (char *) VAL_STRING(&values[etag_col]);
00139                         pres.etag.len = strlen(pres.etag.s);
00140                         event.s = (char *) VAL_STRING(&values[event_col]);
00141                         event.len = strlen(event.s);
00142                         pres.event= contains_event(&event, NULL);
00143                         if(pres.event== NULL)
00144                         {
00145                                 LM_ERR("event not found\n");
00146                                 goto error;
00147                         }
00148 
00149                         if(uandd_to_uri(pres.user, pres.domain, &uri)< 0)
00150                         {
00151                                 LM_ERR("constructing uri\n");
00152                                 goto error;
00153                         }
00154                 
00155                         /* delete from hash table */
00156                         if(publ_cache_enabled && delete_phtable(&uri, pres.event->type)< 0)
00157                         {
00158                                 LM_ERR("deleting from pres hash table\n");
00159                                 goto error;
00160                         }
00161 
00162                         LM_DBG("found expired publish for [user]=%.*s  [domanin]=%.*s\n",
00163                                 pres.user.len,pres.user.s, pres.domain.len, pres.domain.s);
00164 
00165                         if (pres_notifier_processes > 0)
00166                         {
00167                                 if ((num_watchers = publ_notify_notifier(uri, pres.event)) < 0)
00168                                 {
00169                                         LM_ERR("Updating watcher records\n");
00170                                         goto error;
00171                                 }
00172 
00173                                 if (num_watchers > 0)
00174                                 {
00175                                         if (mark_presentity_for_delete(&pres) < 0)
00176                                         {
00177                                                 LM_ERR("Marking presentity\n");
00178                                                 goto error;
00179                                         }
00180                                 }
00181                                 else
00182                                 {
00183                                         if (delete_presentity(&pres) < 0)
00184                                         {
00185                                                 LM_ERR("Deleting presentity\n");
00186                                                 goto error;
00187                                         }
00188                                 }
00189                         }
00190                         else
00191                         {
00192                                 if(pres.event->get_rules_doc && 
00193                                         pres.event->get_rules_doc(&pres.user,
00194                                                                         &pres.domain,
00195                                                                         &rules_doc)< 0)
00196                                 {
00197                                         LM_ERR("getting rules doc\n");
00198                                         goto error;
00199                                 }
00200                                 if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc)< 0)
00201                                 {
00202                                         LM_ERR("sending Notify request\n");
00203                                         goto error;
00204                                 }
00205                                 if(rules_doc)
00206                                 {
00207                                         if(rules_doc->s)
00208                                                 pkg_free(rules_doc->s);
00209                                         pkg_free(rules_doc);
00210                                         rules_doc= NULL;
00211                                 }
00212                         }
00213 
00214                         pkg_free(uri.s);
00215                         uri.s = NULL;
00216                 }
00217         } while (db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
00218                         && RES_ROW_N(result) > 0);
00219 
00220         pa_dbf.free_result(pa_db, result);
00221         result = NULL;
00222 
00223         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
00224         {
00225                 LM_ERR("in use_table\n");
00226                 goto error;
00227         }
00228 
00229         if (pres_notifier_processes == 0)
00230         {
00231 delete_pres:
00232                 if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, n_db_cols) < 0) 
00233                         LM_ERR("failed to delete expired records from DB\n");
00234         }
00235 
00236         return;
00237 
00238 error:
00239         if(result)
00240                 pa_dbf.free_result(pa_db, result);
00241         if(uri.s) pkg_free(uri.s);
00242         if(rules_doc)
00243         {
00244                 if(rules_doc->s)
00245                         pkg_free(rules_doc->s);
00246                 pkg_free(rules_doc);
00247         }
00248 
00249         return;
00250 }
00251 
00256 int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2)
00257 {
00258         struct sip_uri puri;
00259         str body;
00260         int lexpire;
00261         presentity_t* presentity = 0;
00262         struct hdr_field* hdr;
00263         int found= 0, etag_gen = 0;
00264         str etag={0, 0};
00265         str* sender= NULL;
00266         static char buf[256];
00267         int buf_len= 255;
00268         pres_ev_t* event= NULL;
00269         str pres_user;
00270         str pres_domain;
00271         int reply_code;
00272         str reply_str;
00273         int sent_reply= 0;
00274         char* sphere= NULL;
00275 
00276         reply_code= 500;
00277         reply_str= pu_500_rpl;
00278 
00279         counter++;
00280         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
00281         {
00282                 LM_ERR("parsing headers\n");
00283                 reply_code= 400;
00284                 reply_str= pu_400a_rpl;
00285                 goto error;
00286         }
00287         memset(&body, 0, sizeof(str));
00288         
00289         /* inspecting the Event header field */
00290         
00291         if(msg->event && msg->event->body.len > 0)
00292         {
00293                 if (!msg->event->parsed && (parse_event(msg->event) < 0))
00294                 {
00295                         LM_ERR("cannot parse Event header\n");
00296                         reply_code= 400;
00297                         reply_str= pu_400a_rpl;
00298                         goto error;
00299                 }
00300         }
00301         else
00302                 goto unsupported_event;
00303 
00304         /* search event in the list */
00305         event= search_event((event_t*)msg->event->parsed);
00306         if(event== NULL)
00307         {
00308                 goto unsupported_event;
00309         }
00310         
00311         /* examine the SIP-If-Match header field */
00312         hdr = msg->headers;
00313         while (hdr!= NULL)
00314         {
00315                 if(cmp_hdrname_strzn(&hdr->name, "SIP-If-Match", 12)==0)
00316                 {
00317                         found = 1;
00318                         break;
00319                 }
00320                 hdr = hdr->next;
00321         }
00322         if(found==0 )
00323         {
00324                 LM_DBG("SIP-If-Match header not found\n");
00325                 etag.s = generate_ETag(0);
00326                 if(etag.s == NULL)
00327                 {
00328                         LM_ERR("when generating etag\n");
00329                         goto error;
00330                 }
00331                 etag.len=(strlen(etag.s));
00332                 etag_gen=1;
00333                 LM_DBG("new etag  = %.*s \n", etag.len, etag.s);
00334         }
00335         else
00336         {
00337                 LM_DBG("SIP-If-Match header found\n");
00338                 etag.s = (char*)pkg_malloc((hdr->body.len+ 1)* sizeof(char));
00339                 if(etag.s== NULL)
00340                 {
00341                         ERR_MEM(PKG_MEM_STR);
00342                 }
00343                 memcpy(etag.s, hdr->body.s, hdr->body.len );
00344                 etag.len = hdr->body.len;        
00345                 etag.s[ etag.len] = '\0';
00346                 LM_DBG("existing etag  = %.*s \n", etag.len, etag.s);
00347         }
00348 
00349         /* examine the expire header field */
00350         if(msg->expires && msg->expires->body.len > 0)
00351         {
00352                 if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
00353                 {
00354                         LM_ERR("cannot parse Expires header\n");
00355                         goto error;
00356                 }
00357                 lexpire = ((exp_body_t*)msg->expires->parsed)->val;
00358                 LM_DBG("Expires header found, value= %d\n", lexpire);
00359 
00360         }
00361         else 
00362         {
00363                 LM_DBG("'expires' not found; default=%d\n",     event->default_expires);
00364                 lexpire = event->default_expires;
00365         }
00366         if(lexpire > max_expires)
00367                 lexpire = max_expires;
00368 
00369         /* get pres_uri from Request-URI*/
00370         if(parse_sip_msg_uri(msg)< 0)
00371         {
00372                 LM_ERR("parsing Request URI\n");
00373                 reply_code= 400; 
00374                 reply_str= pu_400a_rpl;
00375                 goto error;
00376         }
00377         pres_user= msg->parsed_uri.user;
00378         pres_domain= msg->parsed_uri.host;
00379 
00380         if (!msg->content_length) 
00381         {
00382                 LM_ERR("no Content-Length header found!\n");
00383                 reply_code= 400; 
00384                 reply_str= pu_400a_rpl;
00385                 goto error;
00386         }       
00387 
00388         /* process the body */
00389         if ( get_content_length(msg) == 0 )
00390         {
00391                 body.s = NULL;
00392                 if (etag_gen)
00393                 {
00394                         LM_ERR("No E-Tag and no body found\n");
00395                         reply_code= 400;
00396                         reply_str= pu_400b_rpl;
00397                         goto error;
00398                 }
00399         }
00400         else
00401         {
00402                 body.s=get_body(msg);
00403                 if (body.s== NULL) 
00404                 {
00405                         LM_ERR("cannot extract body\n");
00406                         reply_code= 400; 
00407                         reply_str= pu_400a_rpl;
00408                         goto error;
00409                 }
00410                 body.len= get_content_length( msg );
00411 
00412                 if(sphere_enable && event->evp->type == EVENT_PRESENCE &&
00413                                 get_content_type(msg)== SUBTYPE_PIDFXML)
00414                 {
00415                         sphere= extract_sphere(body);                   
00416                 }
00417 
00418         }       
00419         memset(&puri, 0, sizeof(struct sip_uri));
00420         if(sender_uri)
00421         {
00422                 sender=(str*)pkg_malloc(sizeof(str));
00423                 if(sender== NULL)
00424                 {
00425                         ERR_MEM(PKG_MEM_STR);
00426                 }       
00427                 if(pv_printf(msg, (pv_elem_t*)sender_uri, buf, &buf_len)<0)
00428                 {
00429                         LM_ERR("cannot print the format\n");
00430                         goto error;
00431                 }
00432                 if(parse_uri(buf, buf_len, &puri)!=0)
00433                 {
00434                         LM_ERR("bad sender SIP address!\n");
00435                         reply_code= 400; 
00436                         reply_str= pu_400a_rpl;
00437                         goto error;
00438                 } 
00439                 else 
00440                 {
00441                         LM_DBG("using user id [%.*s]\n",buf_len,buf);
00442                 }
00443                 sender->s= buf;
00444                 sender->len= buf_len;
00445         }
00446         /* call event specific handling function*/
00447         if(event->evs_publ_handl)
00448         {
00449                 if(event->evs_publ_handl(msg)< 0)
00450                 {
00451                         LM_ERR("in event specific publish handling\n");
00452                         goto error;
00453                 }
00454         }
00455 
00456         /* now we have all the necessary values */
00457         /* fill in the filds of the structure */
00458 
00459         presentity= new_presentity(&pres_domain, &pres_user, lexpire, event,
00460                         &etag, sender);
00461         if(presentity== NULL)
00462         {
00463                 LM_ERR("creating presentity structure\n");
00464                 goto error;
00465         }
00466 
00467         /* querry the database and update or insert */
00468         if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply, sphere) <0)
00469         {
00470                 LM_ERR("when updating presentity\n");
00471                 goto error;
00472         }
00473 
00474         if(presentity)
00475                 pkg_free(presentity);
00476         if(etag.s)
00477                 pkg_free(etag.s);
00478         if(sender)
00479                 pkg_free(sender);
00480         if(sphere)
00481                 pkg_free(sphere);
00482 
00483         return 1;
00484 
00485 unsupported_event:
00486         
00487         LM_WARN("Missing or unsupported event header field value\n");
00488                 
00489         if(msg->event && msg->event->body.s && msg->event->body.len>0)
00490                 LM_ERR("    event=[%.*s]\n", msg->event->body.len, msg->event->body.s);
00491 
00492         reply_code= BAD_EVENT_CODE;
00493         reply_str=      pu_489_rpl; 
00494 
00495 error:
00496         if(sent_reply== 0)
00497         {
00498                 if(send_error_reply(msg, reply_code, reply_str)< 0)
00499                 {
00500                         LM_ERR("failed to send error reply\n");
00501                 }
00502         }
00503         
00504         if(presentity)
00505                 pkg_free(presentity);
00506         if(etag.s)
00507                 pkg_free(etag.s);
00508         if(sender)
00509                 pkg_free(sender);
00510         if(sphere)
00511                 pkg_free(sphere);
00512 
00513         return -1;
00514 
00515 }
00516 
00517 static int fetch_presentity(str furi, str *presentity)
00518 {
00519         db_key_t query_cols[2], result_cols[1];
00520         db_val_t query_vals[2], *row_vals;
00521         db1_res_t *result;
00522         db_row_t *row;
00523         int n_query_cols = 0, n_result_cols = 0;;
00524         char *tmp;
00525 
00526         query_cols[n_query_cols] = &str_doc_uri_col;
00527         query_vals[n_query_cols].type = DB1_STR;
00528         query_vals[n_query_cols].nul = 0;
00529         query_vals[n_query_cols].val.str_val = furi;
00530         n_query_cols++;
00531 
00532         query_cols[n_query_cols] = &str_doc_type_col;
00533         query_vals[n_query_cols].type = DB1_INT;
00534         query_vals[n_query_cols].nul = 0;
00535         query_vals[n_query_cols].val.int_val = PIDF_MANIPULATION;
00536         n_query_cols++;
00537 
00538         result_cols[n_result_cols++] = &str_doc_col;
00539 
00540         if (pres_xcap_dbf.use_table(pres_xcap_db, &pres_xcap_table) < 0)
00541         {
00542                 LM_ERR("calling use_table()\n");
00543                 return -1;
00544         }
00545 
00546         if (pres_xcap_dbf.query(pres_xcap_db, query_cols, 0, query_vals, result_cols,
00547                                 n_query_cols, n_result_cols, 0, &result) < 0)
00548         {
00549                 LM_ERR("calling query()\n");
00550                 return -1;
00551         }
00552 
00553         if (result == NULL)
00554         {
00555                 LM_ERR("bad result\n");
00556                 return -1;
00557         }
00558 
00559         if (result->n <=0)
00560         {
00561                 pres_xcap_dbf.free_result(pres_xcap_db, result);
00562                 return 0;
00563         }
00564 
00565         if (result->n > 1)
00566         {
00567                 pres_xcap_dbf.free_result(pres_xcap_db, result);
00568                 return -1;
00569         }
00570 
00571         row = &result->rows[0];
00572         row_vals = ROW_VALUES(row);
00573 
00574         tmp = (char *)row_vals[0].val.string_val;
00575         if (tmp == NULL)
00576         {
00577                 LM_ERR("xcap document is empty\n");
00578                 pres_xcap_dbf.free_result(pres_xcap_db, result);
00579                 return -1;
00580         }
00581         presentity->len = strlen(tmp);
00582 
00583         presentity->s = pkg_malloc(presentity->len * sizeof(char));
00584         if (presentity->s == NULL)
00585         {
00586                 LM_ERR("allocating memory\n");
00587                 pres_xcap_dbf.free_result(pres_xcap_db, result);
00588                 return -1;
00589         }
00590         memcpy(presentity->s, tmp, presentity->len);
00591 
00592         pres_xcap_dbf.free_result(pres_xcap_db, result);
00593         return 1;
00594 }
00595 
00596 int pres_update_presentity(struct sip_msg *msg, char *puri, char *furi, char *fname)
00597 {
00598         int pres_result, ret = -1, new_t;
00599         char *sphere = NULL;
00600         str pres_uri, file_uri, filename, presentity, ev;
00601         pres_ev_t *event;
00602         presentity_t *pres = NULL;
00603         struct sip_uri parsed_uri;
00604 
00605         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri)!=0)
00606         {
00607                 LM_ERR("invalid uri parameter");
00608                 return -1;
00609         }
00610         if(fixup_get_svalue(msg, (gparam_p)furi, &file_uri)!=0)
00611         {
00612                 LM_ERR("invalid file_uri parameter");
00613                 return -1;
00614         }
00615         if(fixup_get_svalue(msg, (gparam_p)fname, &filename)!=0)
00616         {
00617                 LM_ERR("invalid filename parameter");
00618                 return -1;
00619         }
00620 
00621         LM_INFO("Hard-state file %.*s (uri %.*s) updated for %.*s\n",
00622                 filename.len, filename.s,
00623                 file_uri.len, file_uri.s,
00624                 pres_uri.len, pres_uri.s);
00625 
00626         if (pres_integrated_xcap_server != 1)
00627         {
00628                 LM_ERR("integrated XCAP server not configured\n");
00629                 return -1;
00630         }
00631 
00632         ev.s = "presence";
00633         ev.len = 8;
00634         event = contains_event(&ev, NULL);
00635         if (event == NULL)
00636         {
00637                 LM_ERR("presence event not supported\n");
00638                 return -1;
00639         }
00640 
00641         if (parse_uri(pres_uri.s, pres_uri.len, &parsed_uri) < 0)
00642         {
00643                 LM_ERR("bad presentity URI\n");
00644                 return -1;
00645         }
00646 
00647         pres_result = fetch_presentity(file_uri, &presentity);
00648         if (pres_result < 0)
00649         {
00650                 LM_ERR("retrieving presentity\n");
00651                 return -1;
00652         }
00653         else if (pres_result > 0)
00654         {
00655                 /* Insert/replace presentity... */
00656                 LM_DBG("INSERT/REPLACE\n");
00657                 xmlDocPtr doc;
00658 
00659                 if (sphere_enable)
00660                         sphere = extract_sphere(presentity);
00661 
00662                 doc = xmlParseMemory(presentity.s, presentity.len);
00663                 if (doc == NULL)
00664                 {
00665                         LM_ERR("bad body format\n");
00666                         xmlFreeDoc(doc);
00667                         xmlCleanupParser();
00668                         xmlMemoryDump();
00669                         goto done;
00670                 }
00671                 xmlFreeDoc(doc);
00672                 xmlCleanupParser();
00673                 xmlMemoryDump();
00674 
00675                 new_t = 1;
00676         }
00677         else
00678         {
00679                 /* Delete presentity... */
00680                 LM_DBG("DELETE\n");
00681                 new_t = 0;
00682         }
00683 
00684         pres = new_presentity(&parsed_uri.host, &parsed_uri.user, -1, event, &filename, NULL);
00685         if (pres == NULL)
00686         {
00687                 LM_ERR("creating presentity structure\n");
00688                 goto done;
00689         }
00690 
00691         if (update_presentity(NULL, pres, &presentity, new_t, NULL, sphere) < 0)
00692         {
00693                 LM_ERR("updating presentity\n");
00694                 goto done;
00695         }
00696 
00697         ret = 1;
00698 
00699 done:
00700         if (pres) pkg_free(pres);
00701         if (sphere) pkg_free(sphere);
00702         if (presentity.s) pkg_free(presentity.s);
00703 
00704         return ret;
00705 }