modules/mi_xmlrpc/xr_writer.c
d70cf5d6
 /*
  * $Id$
  *
  * Copyright (C) 2006 Voice Sistem SRL
  *
9b64b9f3
  * This file is part of Kamailio.
d70cf5d6
  *
9b64b9f3
  * Kamailio is free software; you can redistribute it and/or
d70cf5d6
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
d70cf5d6
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
d70cf5d6
  *
  * History:
  * ---------
  *  2006-11-30  first version (lavinia)
  */
 
 
 #include <string.h>
 #include "../../str.h"
 #include "../../dprint.h"
 #include "../../mem/mem.h"
 #include "xr_writer.h"
 #include "mi_xmlrpc.h"
 
 static char *reply_buffer = 0;
 static unsigned int reply_buffer_len = 0;
 static xmlrpc_value* reply_item;
 
 int xr_writer_init( unsigned int size )
 {
 	reply_buffer_len = size;
 
 	reply_buffer = pkg_malloc(size);
 	if(!reply_buffer){
387847d7
 		LM_ERR("pkg_malloc cannot allocate any more memory!\n");
d70cf5d6
 		return -1;
 	}
 	
 	return 0;
 }
 
 static int xr_write_node(str * buf, struct mi_node * node)
 {
 	char *end;
 	char *p;
     struct mi_attr* attr;
 
 	p = buf->s;
 	end = buf->s + buf->len -1;
 
 	/* name and value */
 	if ( node->name.s != NULL ) {
 		if ( p+node->name.len+3 > end )
 			return -1;
 		memcpy(p, node->name.s, node->name.len);
 		p += node->name.len;
 		*(p++) = ':';
 		*(p++) = ':';
 		*(p++) = ' ';
 	}
 	if ( node->value.s != NULL ) {
 		if ( p+node->value.len > end )
 			return -1;
 		memcpy(p, node->value.s, node->value.len);
 		p += node->value.len;
 	}
 	
 	/* attributes */
 	for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
 		if ( attr->name.s != NULL ) {
 			if ( p+attr->name.len+2 > end )
 				return -1;
 			*(p++) = ' ';
 			memcpy(p,attr->name.s,attr->name.len);
 			p += attr->name.len;
 			*(p++) = '=';
 		}
 		if (attr->value.s!=NULL) {
 			if (p+attr->value.len>end)
 				return -1;
 			memcpy(p,attr->value.s,attr->value.len);
 			p += attr->value.len;
 		}
 	}
 
 
 	if ( p+1 > end )
 		return -1;
 	*(p++) = '\n';
 
 	buf->len -= p-buf->s; 
 	buf->s = p;
 	return 0;
 }
 
 static int recur_build_response_array( xmlrpc_env * env, struct mi_node * tree, str * buf )
 {
 	for ( ; tree ; tree = tree->next ) {
 		
 		if ( xr_write_node( buf, tree ) != 0 ) {
387847d7
 			LM_ERR("failed to get MI node data!\n");
d70cf5d6
 			return -1;
 		}	
 
 		reply_buffer[reply_buffer_len-buf->len] = 0;
 		reply_item = xmlrpc_build_value(env, "s", reply_buffer);
 		xmlrpc_array_append_item(env, xr_response, reply_item);
 		
 		buf->s = reply_buffer; 
 		buf->len = reply_buffer_len;
 
 		if ( tree->kids ) {
 			if ( recur_build_response_array(env, tree->kids, buf) != 0 )
 				return -1;
 		}
 	}
 	return 0;
 }
 
 int xr_build_response_array( xmlrpc_env * env, struct mi_root * tree )
 {
 	str buf;
     
 	buf.s = reply_buffer;
 	buf.len = reply_buffer_len;
 
 	/* test if mi root value is 200 OK (if not no point to continue) */
 	if ( tree->code<200 || tree->code>=300 ){
387847d7
 		LM_DBG("command processing failure: %s\n", tree->reason.s); 
d70cf5d6
 		if (tree->reason.s)
 			xmlrpc_env_set_fault(env, tree->code, tree->reason.s);
 		else
 			xmlrpc_env_set_fault(env, tree->code, "Error");
 		goto error;
 	}
 	
 	if ( recur_build_response_array(env, (&tree->node)->kids, &buf) != 0 ) {
387847d7
 		LM_ERR("failed to read from the MI tree!\n");
d70cf5d6
 		xmlrpc_env_set_fault(env, 500, "Failed to write reply");
 		goto error;
 	}
 
 	return 0;
 
 error:
 	if ( reply_buffer ) pkg_free(reply_buffer);
 	return -1;
 }
 
 static int recur_build_response( xmlrpc_env * env, struct mi_node * tree, str * buf )
 {
    	for ( ; tree ; tree = tree->next ) {
 		
 		if ( xr_write_node( buf, tree ) != 0 ) {
 		
 			reply_buffer = (char*) pkg_realloc ( reply_buffer, 2*reply_buffer_len);
 
 			if ( !reply_buffer ){
387847d7
 				LM_ERR("pkg_realloc cannot reallocate any more memory!\n");
d70cf5d6
 				return -1;
 			}
 
 			buf->s = reply_buffer +(reply_buffer_len - buf->len);
 			buf->len += reply_buffer_len;
 			reply_buffer_len *=2 ;
 
 			if ( xr_write_node( buf, tree ) != 0 ) {
387847d7
 				LM_ERR("failed to get MI node data!\n");
d70cf5d6
 				return -1;
 			}
 		}
 
 		if ( tree->kids ) {
 			if ( recur_build_response(env, tree->kids, buf) != 0 )
 				return -1;
 		}
 	}
 
 	return 0;
 }
 
 char* xr_build_response( xmlrpc_env * env, struct mi_root * tree )
 {
 	str buf;
 	
 	buf.s = reply_buffer;
 	buf.len = reply_buffer_len;
 
 	if ( tree->code<200 || tree->code>=300 ){
387847d7
 		LM_DBG("command processing failure: %s\n", tree->reason.s); 
d70cf5d6
 		if (tree->reason.s)
 			xmlrpc_env_set_fault(env, tree->code, tree->reason.s);
 		else
 			xmlrpc_env_set_fault(env, tree->code, "Error");
 		return 0;
 	}
 	
 	if ( recur_build_response(env, (&tree->node)->kids, &buf) != 0 ) {
387847d7
 		LM_ERR("failed to read from the MI tree!\n");
0b305412
 		xmlrpc_env_set_fault(env, 500, "Failed to build reply");
d70cf5d6
 		return 0;
 	}
 	
 	reply_buffer[reply_buffer_len-buf.len] = 0;
 
 	return reply_buffer;
 }