presence_conference/notify_body.c

Go to the documentation of this file.
00001 /*
00002  * presence_conference module - mariusbucur
00003  *
00004  * Copyright (C) 2010 Marius Bucur
00005  * Copyright (C) 2006 Voice Sistem S.R.L.
00006  * Copyright (C) 2008 Klaus Darilion, IPCom
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  * 2010-07-12  initial version (mariusbucur)
00027  */
00033 #define MAX_INT_LEN 11 /* 2^32: 10 chars + 1 char sign */
00034 
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <libxml/parser.h>
00038 
00039 #include "../../mem/mem.h"
00040 #include "../presence/utils_func.h"
00041 #include "../presence/hash.h"
00042 #include "../presence/event_list.h"
00043 #include "../presence/presence.h"
00044 #include "../presence/presentity.h"
00045 #include "notify_body.h"
00046 #include "pidf.h"
00047 
00048 str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n, int off_index);
00049 
00050 void free_xml_body(char* body)
00051 {
00052         if(body== NULL)
00053                 return;
00054 
00055         xmlFree(body);
00056 }
00057 
00058 
00059 str* conf_agg_nbody(str* pres_user, str* pres_domain, str** body_array, int n, int off_index)
00060 {
00061         str* n_body= NULL;
00062 
00063         LM_DBG("[pres_user]=%.*s [pres_domain]= %.*s, [n]=%d\n",
00064                         pres_user->len, pres_user->s, pres_domain->len, pres_domain->s, n);
00065 
00066         if(body_array== NULL)
00067                 return NULL;
00068 
00069         n_body = agregate_xmls(pres_user, pres_domain, body_array, n, off_index);
00070         LM_DBG("[n_body]=%p\n", n_body);
00071         if(n_body) {
00072                 LM_DBG("[*n_body]=%.*s\n",
00073                         n_body->len, n_body->s);
00074         }
00075         if(n_body== NULL && n!= 0)
00076         {
00077                 LM_ERR("while aggregating body\n");
00078         }
00079 
00080         return n_body;
00081 }       
00082 
00083 str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n, int off_index)
00084 {
00085         int i, j = 0;
00086         
00087         if(body_array == NULL || n == 0)
00088                 return 0;
00089 
00090         xmlDocPtr  doc = NULL;
00091         xmlNodePtr root_node = NULL;
00092         xmlNsPtr   namespace = NULL;
00093 
00094         xmlNodePtr p_root= NULL;
00095         xmlDocPtr* xml_array ;
00096         xmlNodePtr node = NULL;
00097         str *body= NULL;
00098         char buf[MAX_URI_SIZE+1];
00099 
00100         LM_DBG("[pres_user]=%.*s [pres_domain]= %.*s, [n]=%d\n",
00101                         pres_user->len, pres_user->s, pres_domain->len, pres_domain->s, n);
00102 
00103         xml_array = (xmlDocPtr*)pkg_malloc( n*sizeof(xmlDocPtr) );
00104         if(unlikely(xml_array == NULL))
00105         {
00106                 LM_ERR("while allocating memory");
00107                 return NULL;
00108         }
00109         memset(xml_array, 0, n*sizeof(xmlDocPtr)) ;
00110 
00111         /* parse all the XML documents */
00112         for(i=0; i<n; i++)
00113         {
00114                 if(body_array[i] == NULL )
00115                         continue;
00116 
00117                 xml_array[j] = xmlParseMemory( body_array[i]->s, body_array[i]->len );
00118                 
00119                 /* LM_DBG("parsing XML body: [n]=%d, [i]=%d, [j]=%d xml_array[j]=%p\n", n, i, j, xml_array[j] ); */
00120 
00121                 if(unlikely(xml_array[j] == NULL))
00122                 {
00123                         LM_ERR("while parsing xml body message\n");
00124                         goto error;
00125                 }
00126                 j++;
00127                 
00128         }
00129 
00130         if(j == 0)  /* no body */
00131         {
00132                 if(xml_array)
00133                         pkg_free(xml_array);
00134                 return NULL;
00135         }
00136 
00137         /* n: number of bodies in total */
00138         /* j: number of useful bodies; created XML structures */
00139         /* i: loop counter */
00140         /* LM_DBG("number of bodies in total [n]=%d, number of useful bodies [j]=%d\n", n, j ); */
00141 
00142         /* create the new NOTIFY body  */
00143         if ( (pres_user->len + pres_domain->len + 1) > MAX_URI_SIZE ) {
00144                 LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE);
00145                 return NULL;
00146         }
00147         memcpy(buf, pres_user->s, pres_user->len);
00148         buf[pres_user->len] = '@';
00149         memcpy(buf + pres_user->len + 1, pres_domain->s, pres_domain->len);
00150         buf[pres_user->len + 1 + pres_domain->len]= '\0';
00151 
00152         doc = xmlNewDoc(BAD_CAST "1.0");
00153         if(unlikely(doc == NULL))
00154                 goto error;
00155 
00156         root_node = xmlNewNode(NULL, BAD_CAST "conference-info");
00157         if(unlikely(root_node == NULL))
00158                 goto error;
00159 
00160         xmlDocSetRootElement(doc, root_node);
00161         namespace = xmlNewNs(root_node, BAD_CAST "urn:ietf:params:xml:ns:conference-info", NULL);
00162         if (unlikely(namespace == NULL)) {
00163                 LM_ERR("creating namespace failed\n");
00164                 goto error;
00165         }
00166         xmlSetNs(root_node, namespace);
00167         /* The version must be increased for each new document and is a 32bit int.
00168            The aux_body_processing function will take care of setting the right attribute
00169            depending on the subscription for which the notify is being sent.
00170         */
00171         xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0");
00172         xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "full" );
00173         xmlNewProp(root_node, BAD_CAST "entity", BAD_CAST buf);
00174 
00175         /* loop over all bodies and create the aggregated body */
00176         for(i=0; i<j; i++)
00177         {
00178                 p_root= xmlDocGetRootElement(xml_array[i]);
00179                 if(unlikely(p_root == NULL)) {
00180                         LM_ERR("while geting the xml_tree root element\n");
00181                         goto error;
00182                 }
00183                 /* just checking that the root element is "conference-info" as it should RFC4575 */
00184                 if(unlikely(xmlStrcasecmp(p_root->name, BAD_CAST "conference-info") != 0))
00185                 {
00186                         LM_ERR("root element is not \"conference-info\"\n");
00187                         goto error;
00188                 }
00189                 /* the root "conference-info" element should always have children */
00190                 if (p_root->children) {
00191                         for (node = p_root->children; node != NULL; node = node->next) {
00192                                         if(xmlAddChild(root_node, xmlCopyNode(node, 1)) == NULL) {
00193                                                 LM_ERR("while adding child\n");
00194                                                 goto error;
00195                                         }
00196                         }
00197                 }
00198                 /* we only take the most recent subscription as
00199                    in this phase non partial states will be sent
00200                 */
00201                 if(i != off_index)
00202                         break;
00203         }
00204 
00205         body = (str*)pkg_malloc(sizeof(str));
00206         if(body == NULL) {
00207                 ERR_MEM(PKG_MEM_STR);
00208         }
00209 
00210         xmlDocDumpFormatMemory(doc,(xmlChar**)(void*)&body->s, 
00211                         &body->len, 1); 
00212 
00213         for(i=0; i<j; i++)
00214         {
00215                 if(xml_array[i]!=NULL)
00216                         xmlFreeDoc(xml_array[i]);
00217         }
00218         if (doc)
00219                 xmlFreeDoc(doc);
00220         if(xml_array!=NULL)
00221                 pkg_free(xml_array);
00222     
00223         return body;
00224 
00225 error:
00226         LM_ERR("error in presence_conference agg_nbody\n");
00227         if(xml_array!=NULL)
00228         {
00229                 for(i=0; i<j; i++)
00230                 {
00231                         if(xml_array[i]!=NULL)
00232                                 xmlFreeDoc(xml_array[i]);
00233                 }
00234                 pkg_free(xml_array);
00235         }
00236         if(body)
00237                 pkg_free(body);
00238 
00239         return NULL;
00240 }
00241 
00242 str *conf_body_setversion(subs_t *subs, str *body) {
00243         char version_str[MAX_INT_LEN + 2];//for the null terminating character \0
00244         snprintf(version_str, MAX_INT_LEN, "%d", subs->version);
00245         if (!body) {
00246                 return NULL;
00247         }
00248         
00249         xmlDocPtr doc = xmlParseMemory(body->s, body->len);
00250         if(!doc) {
00251                 goto error;
00252         }
00253         xmlNodePtr conf_info = xmlDocGetRootElement(doc);
00254         if(!conf_info) {
00255                 goto error;
00256         }
00257         if(!xmlSetProp(conf_info, BAD_CAST "version", BAD_CAST version_str)) {
00258                 goto error;
00259         }
00260         xmlDocDumpFormatMemory(doc,(xmlChar**)(void*)&body->s, 
00261                         &body->len, 1);
00262         return NULL;
00263 error:
00264         LM_ERR("error in presence_conference conf_body_setversion\n");
00265         return NULL;
00266 }