/*
 * pua_xmpp module - presence SIP - XMPP Gateway
 *
 * Copyright (C) 2007 Voice Sistem S.R.L.
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or 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
 *
 * opensips is distributed in the hope that it will be useful,
 * 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
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * History:
 * --------
 *  2007-03-29  initial version (anca)
 */
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>

#include "../../ut.h"
#include "../../str.h"
#include "../../dprint.h"
#include "../../parser/msg_parser.h"
#include "../../parser/parse_from.h"
#include "../../parser/parse_expires.h"
#include "../../parser/parse_content.h"
#include "../../parser/parse_fline.h"
#include "../../mem/mem.h"
#include "pua_xmpp.h"
#include "simple2xmpp.h"

#define URI_BUF_LEN  256
#define URI_ADD_NULL_TERM(dst, buf, src) \
	do{\
		if(src->len+1 > URI_BUF_LEN) {\
			LM_ERR("Length exceeds buffer len [%d]\n", URI_BUF_LEN);\
			goto error;\
		}\
		memcpy(buf, src->s+4, src->len-4);\
		buf[src->len-4]= '\0';\
		dst.s = buf;\
		dst.len= src->len-4;\
	}while(0)

int winfo2xmpp(str* to_uri, str* body, str* id);
int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, int is_terminated);

int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2)
{
	struct to_body *pto, *pfrom= NULL;
	str to_uri;
	str from_uri={0, 0};
	struct hdr_field* hdr= NULL;
	str body;
	int is_terminated= 0;
	str id;
	ua_pres_t dialog;
	int event_flag= 0;
	char buf_to[256];

	memset(&dialog, 0, sizeof(ua_pres_t));

	LM_DBG("start...\n");

	if( parse_headers(msg,HDR_EOH_F, 0)==-1 )
	{
		LM_ERR("parsing headers\n");
		return -1;
	}
	if((!msg->event ) ||(msg->event->body.len<=0))
	{
		LM_ERR("Missing event header field value\n");
		return -1;
	}

	if( msg->to==NULL || msg->to->body.s==NULL)
	{
		LM_ERR("cannot parse TO header\n");
		return -1;
	}

	pto = get_to(msg);
	if (pto == NULL || pto->error != PARSE_OK) {
		LM_ERR("failed to parse TO header\n");
		return -1;
	}

	dialog.watcher_uri= &pto->uri;

	URI_ADD_NULL_TERM(to_uri, buf_to, dialog.watcher_uri);

	if (pto->tag_value.s==NULL || pto->tag_value.len==0 )
	{
		LM_ERR("to tag value not parsed\n");
		goto error;
	}
	id=  pto->tag_value;
	dialog.from_tag= id;

	if( msg->callid==NULL || msg->callid->body.s==NULL)
	{
		LM_ERR("cannot parse callid header\n");
		goto error;
	}
	dialog.call_id = msg->callid->body;

	if (!msg->from || !msg->from->body.s)
	{
		LM_ERR("ERROR cannot find 'from' header!\n");
		goto error;
	}
	if (msg->from->parsed == NULL)
	{
		/* parsing from header */
		if ( parse_from_header( msg )<0 )
		{
			LM_ERR("ERROR cannot parse From header\n");
			goto error;
		}
	}
	pfrom = (struct to_body*)msg->from->parsed;
	dialog.pres_uri= &pfrom->uri;

	from_uri.s = xmpp_uri_sip2xmpp(dialog.pres_uri);
	if(from_uri.s == 0)
	{
		LM_ERR("Failed to translate uri from sip to xmpp [%.*s]\n",
				dialog.pres_uri->len, dialog.pres_uri->s);
		goto error;
	}
	from_uri.len= strlen(from_uri.s);

	if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
	{
		LM_ERR("no from tag value present\n");
		goto error;
	}

	dialog.to_tag= pfrom->tag_value;
	dialog.flag|= XMPP_SUBSCRIBE;
	if(msg->event->body.len== 8 &&
			(strncasecmp(msg->event->body.s,"presence",8 )==0))
		event_flag|= PRESENCE_EVENT;
	else
	if(msg->event->body.len== 14 &&
			(strncasecmp(msg->event->body.s,"presence.winfo",14 )==0))
		event_flag|= PWINFO_EVENT;
	else
	{
		LM_ERR("wrong event\n");
		goto error;
	}
	dialog.event= event_flag;

	if(pua_is_dialog(&dialog)< 0) // verify if within a stored dialog
	{
		LM_ERR("Notify in a non existing dialog\n");
		goto error;
	}
	/*constructing the xml body*/
	if(get_content_length(msg) == 0 )
	{
		body.s= NULL;
		body.len= 0;
	}
	else
	{
		if ( get_body(msg,&body)!=0 || body.len==0)
		{
			LM_ERR("cannot extract body from msg\n");
			goto error;
		}
	}

	/* treat the two cases: event= presence & event=presence.winfo */
	if(event_flag & PRESENCE_EVENT)
	{
		LM_DBG("PRESENCE\n");
		hdr = get_header_by_static_name( msg, "Subscription-State" );
		if(hdr && strncasecmp(hdr->body.s,"terminated", 10)== 0)
		{
			/* chack if reason timeout => don't send notification */
			if(strncasecmp(hdr->body.s+11,"reason=timeout", 14)== 0)
			{
				LM_DBG("Received Notification with state"
					"terminated; reason= timeout=> don't send notification\n");
				return 1;
			}
			is_terminated= 1;

		}

		if(build_xmpp_content(&to_uri, &from_uri, &body, &id, is_terminated)< 0)
		{
			LM_ERR("in function build_xmpp_content\n");
			goto error;
		}
	}
	else
	{
		if(event_flag & PWINFO_EVENT)
		{
			LM_DBG("PRESENCE.WINFO\n");
			hdr = get_header_by_static_name( msg, "Subscription-State" );
			if(hdr && strncasecmp(hdr->body.s,"terminated", 10)== 0)
			{
				LM_DBG("Notify for presence.winfo with"
					" Subscription-State terminated- should not translate\n");
				goto error;
			}
			if(winfo2xmpp(&to_uri, &body, &id)< 0)
			{
				LM_ERR("while sending subscription\n");
				goto error;
			}

		}
		else
		{
			LM_ERR("Missing or unsupported event header field value\n");
			goto error;
		}

	}
	return 1;

error:
	return 0;
}

int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id,
		int is_terminated)
{
	xmlDocPtr sip_doc= NULL;
	xmlDocPtr doc= NULL;
	xmlNodePtr xmpp_root= NULL;
	xmlNodePtr sip_root= NULL;
	xmlNodePtr new_node= NULL;
	xmlNodePtr node = NULL;
	xmlBufferPtr buffer= NULL;
	xmlAttrPtr attr= NULL;
	char* basic= NULL, *priority= NULL, *note= NULL;
	str xmpp_msg;

	LM_DBG("start...\n");

	/* creating the xml doc for the xmpp message*/
	doc= xmlNewDoc(0);
	if(doc== NULL)
	{
		LM_ERR("when creating new xml doc\n");
		goto error;
	}
	xmpp_root = xmlNewNode(NULL, BAD_CAST "presence");
	if(xmpp_root==0)
	{
		LM_ERR("when adding new node- presence\n");
		goto error;
	}
	xmlDocSetRootElement(doc, xmpp_root);

	attr= xmlNewProp(xmpp_root, BAD_CAST "to", BAD_CAST to_uri->s);
	if(attr== NULL)
	{
		LM_ERR("while adding new attribute\n");
		goto error;
	}
	attr= xmlNewProp(xmpp_root, BAD_CAST "from", BAD_CAST from_uri->s);
	if(attr== NULL)
	{
		LM_ERR("while adding new attribute\n");
		goto error;
	}
	if(is_terminated)
	{
		attr=  xmlNewProp(xmpp_root, BAD_CAST "type", BAD_CAST "unsubscribed");
		if(attr== NULL)
		{
			LM_ERR("while adding new attribute\n");
			goto error;
		}
		goto done;
	}
	if(body->s== NULL)
	{
		attr=  xmlNewProp(xmpp_root, BAD_CAST "type", BAD_CAST "unavailable");
		if(attr== NULL)
		{
			LM_ERR("while adding new attribute\n");
			goto error;
		}
		goto done;
	}

	/*extractiong the information from the sip message body*/
	sip_doc= xmlParseMemory(body->s, body->len);
	if(sip_doc== NULL)
	{
		LM_ERR("while parsing xml memory\n");
		return -1;
	}
	sip_root= XMLDocGetNodeByName(sip_doc, "presence", NULL);
	if(sip_root== NULL)
	{
		LM_ERR("while extracting 'presence' node\n");
		goto error;
	}

	node = XMLNodeGetNodeByName(sip_root, "basic", NULL);
	if(node== NULL)
	{
		LM_ERR("while extracting status basic node\n");
		goto error;
	}
	basic= (char*)xmlNodeGetContent(node);
	if(basic== NULL)
	{
		LM_ERR("while extracting status basic node content\n");
		goto error;
	}
	if(xmlStrcasecmp( (unsigned char*)basic,(unsigned char*) "closed")==0 )
	{
		attr= xmlNewProp(xmpp_root, BAD_CAST "type", BAD_CAST "unavailable");
		if(attr== NULL)
		{
			LM_ERR("while adding node attr\n");
			xmlFree(basic);
			goto error;
		}
		xmlFree(basic);
		goto done;
	}/* else the status is open so no type attr should be added */

	xmlFree(basic);
	/* addind show node */
	node= XMLNodeGetNodeByName(sip_root, "note", NULL);
	if(node== NULL)
	{
		LM_DBG("No note node found\n");
		node= XMLNodeGetNodeByName(sip_root, "person", NULL);
		if(node== NULL)
		{
			LM_DBG("No person node found\n");
			goto done;
		}
		node= XMLNodeGetNodeByName(node, "note", NULL);
		if(node== NULL)
		{
			LM_DBG("Person node has no note node\n");
			goto done;
		}
	}
	note= (char*)xmlNodeGetContent(node);
	if(note== NULL)
	{
		LM_ERR("while extracting note node content\n");
		goto error;
	}

	if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"away")== 0)
	{
		new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show",
				BAD_CAST "away");
		if(new_node== NULL)
		{
			LM_ERR("while adding node show: away\n");
			goto error;
		}
	}
	else
		if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"busy")== 0)
		{
			new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show"
					, BAD_CAST "xa");
			if(new_node== NULL)
			{
				LM_ERR("while adding node show: away\n");
				goto error;
			}
		}

		/*
		if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"on the phone")== 0)
		{
			new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show", BAD_CAST "chat");
			if(new_node== NULL)
			{
				LM_ERR("while adding node show: chat\n");
				goto error;
			}
		}
		else
			if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"idle")== 0)
			{
				new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show", BAD_CAST "idle");
				if(new_node== NULL)
				{
					LM_ERR("while adding node: idle\n");
					goto error;
				}
			}
			else */
				if((xmlStrcasecmp((unsigned char*)note,
					(unsigned char*)"dnd")== 0)||
					(xmlStrcasecmp((unsigned char*)note,
						(unsigned char*)"do not disturb")== 0))
				{
					new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show",
							BAD_CAST "dnd");
					if(new_node== NULL)
					{
						LM_ERR("while adding node show: dnd\n");
						goto error;
					}
				}


	/* adding status node */
	new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "status", BAD_CAST note);
	if(new_node== NULL)
	{
		LM_ERR("while adding node status\n");
		goto error;
	}

	xmlFree(note);
	note= NULL;

	/* adding priotity node*/
	node= XMLNodeGetNodeByName(sip_root, "contact", NULL);
	if(node== NULL)
	{
		LM_DBG("No contact node found\n");
	}
	else
	{
		priority= XMLNodeGetAttrContentByName(node, "priority");
		if(priority== NULL)
			LM_DBG("No priority attribute found\n");
		else
		{
			new_node= xmlNewChild(xmpp_root, NULL, BAD_CAST "priority",
					BAD_CAST priority);
			if(sip_root== NULL)
			{
				LM_ERR("while adding node\n");
				xmlFree(priority);
				goto error;
			}
			xmlFree(priority);
		}
	}

done:
	buffer= xmlBufferCreate();
	if(buffer== NULL)
	{
		LM_ERR("while adding creating new buffer\n");
		goto error;
	}

	xmpp_msg.len= xmlNodeDump(buffer, doc, xmpp_root, 1,1);
	if(xmpp_msg.len== -1)
	{
		LM_ERR("while dumping node\n");
		goto error;
	}
	xmpp_msg.s= (char*)xmlBufferContent( buffer);
	if(xmpp_msg.s==  NULL)
	{
		LM_ERR("while extracting buffer content\n");
		goto error;
	}

	LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s);
	if( xmpp_notify(from_uri, to_uri, &xmpp_msg, id)< 0)
	{
		LM_ERR("while sending xmpp_notify\n");
		goto error;
	}

	xmlBufferFree(buffer);
	xmlCleanupParser();
	xmlMemoryDump();

	if(sip_doc)
		xmlFreeDoc(sip_doc);
	if(doc)
		xmlFreeDoc(doc);
	return 0;

error:
	if(sip_doc)
		xmlFreeDoc(sip_doc);
	if(doc)
		xmlFreeDoc(doc);
	if(note)
		xmlFree(note);
	if(buffer)
		xmlBufferFree(buffer);
	xmlCleanupParser();
	xmlMemoryDump();

	return -1;

}


int winfo2xmpp(str* to_uri, str* body, str* id)
{
	xmlAttrPtr attr= NULL;
	str xmpp_msg;
	char* watcher= NULL ;
	str from_uri = {0, 0};
	xmlDocPtr notify_doc= NULL;
	xmlDocPtr doc= NULL;
	xmlNodePtr pidf_root= NULL;
	xmlNodePtr root_node= NULL;
	xmlNodePtr node= NULL;
	xmlBufferPtr buffer= NULL;
	str watcher_str;

	LM_DBG("start...\n");
	notify_doc= xmlParseMemory(body->s, body->len);
	if(notify_doc== NULL)
	{
		LM_ERR("while parsing xml memory\n");
		return -1;
	}
	pidf_root= XMLDocGetNodeByName(notify_doc, "watcherinfo", NULL);
	if(pidf_root== NULL)
	{
		LM_ERR("while extracting 'presence' node\n");
		goto error;
	}

	node = XMLNodeGetNodeByName(pidf_root, "watcher", NULL);

	for (; node!=NULL; node = node->next)
	{
		if( xmlStrcasecmp(node->name,(unsigned char*)"watcher"))
			continue;

		watcher= (char*)xmlNodeGetContent(node->children);
		if(watcher== NULL)
		{
			LM_ERR("while extracting watcher node content\n");
			goto error;
		}
		watcher_str.s = watcher;
		watcher_str.len = strlen(watcher);

		from_uri.s = xmpp_uri_sip2xmpp(&watcher_str);
		if(from_uri.s == NULL)
		{
			LM_ERR("Failed to transform uri from sip to xmpp\n");
			goto error;
		}
		from_uri.len = strlen(from_uri.s);
		xmlFree(watcher);
		watcher= NULL;

		doc= xmlNewDoc( 0 );
		if(doc== NULL)
		{
			LM_ERR("when creating new xml doc\n");
			goto error;
		}
		root_node = xmlNewNode(NULL, BAD_CAST "presence");
		if(root_node== NULL)
		{
			LM_ERR("when adding new node\n");
			goto error;
		}
		xmlDocSetRootElement(doc, root_node);

		attr= xmlNewProp(root_node, BAD_CAST "to", BAD_CAST to_uri->s);
		if(attr== NULL)
		{
			LM_ERR("while adding attribute to_uri\n");
			goto error;
		}
		attr= xmlNewProp(root_node, BAD_CAST "from", BAD_CAST from_uri.s);
		if(attr== NULL)
		{
			LM_ERR("while adding attribute from_uri\n");
			goto error;
		}
		attr= xmlNewProp(root_node, BAD_CAST "type", BAD_CAST "subscribe");
		if(attr== NULL)
		{
			LM_ERR("while adding attribute type\n");
			goto error;
		}
		buffer= xmlBufferCreate();
		if(buffer== NULL)
		{
			LM_ERR("while adding creating new buffer\n");
			goto error;
		}

		xmpp_msg.len= xmlNodeDump(buffer, doc, root_node, 1,1);
		if(xmpp_msg.len== -1)
		{
			LM_ERR("while dumping node\n");
			goto error;
		}
		xmpp_msg.s= (char*)xmlBufferContent( buffer);
		if(xmpp_msg.s==  NULL)
		{
			LM_ERR("while extracting buffer content\n");
			goto error;
		}

		LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s);

		if( xmpp_subscribe(&from_uri, to_uri, &xmpp_msg, id)< 0)
		{
			LM_ERR("while sending xmpp_subscribe\n");
			goto error;
		}
		xmlBufferFree(buffer);
		buffer= NULL;
		xmlFreeDoc(doc);
		doc= NULL;
	}

	xmlFreeDoc(notify_doc);
	xmlCleanupParser();
	xmlMemoryDump();
	return 0;

error:

	if(doc)
		xmlFreeDoc(doc);
	if(notify_doc)
		xmlFreeDoc(notify_doc);
	if(watcher)
		xmlFree(watcher);
	if(buffer)
		xmlBufferFree(buffer);
	xmlCleanupParser();
	xmlMemoryDump();

	return -1;
}

char* get_error_reason(int code, str* reason)
{
	char* err_cond= NULL;

	err_cond= (char*)pkg_malloc(50* sizeof(char));
	if(err_cond== NULL)
	{
		LM_ERR("no more memory\n");
		return NULL;
	}

	switch( code )
	{
		case 300:	{ strcpy(err_cond, "redirect");					break;}
		case 301:	{ strcpy(err_cond, "gone");						break;}
		case 302:	{ strcpy(err_cond, "redirect");					break;}
		case 305:	{ strcpy(err_cond, "redirect");					break;}
		case 380:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 400:	{ strcpy(err_cond, "bad-request");				break;}
		case 401:	{ strcpy(err_cond, "not-authorized");			break;}
		case 402:	{ strcpy(err_cond, "payment-required");			break;}
		case 403:	{ strcpy(err_cond, "forbidden");				break;}
		case 404:	{ strcpy(err_cond, "item-not-found");			break;}
		case 405:	{ strcpy(err_cond, "not-allowed");				break;}
		case 406:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 407:	{ strcpy(err_cond, "registration-required");	break;}
		case 408:	{ strcpy(err_cond, "service-unavailable");		break;}
		case 410:	{ strcpy(err_cond, "gone");						break;}
		case 413: 	{ strcpy(err_cond, "bad-request");				break;}
		case 414:	{ strcpy(err_cond, "bad-request");				break;}
		case 415:	{ strcpy(err_cond, "bad-request");				break;}
		case 416:	{ strcpy(err_cond, "bad-request");				break;}
		case 420:	{ strcpy(err_cond, "bad-request");				break;}
		case 421:	{ strcpy(err_cond, "bad-request");				break;}
		case 423:	{ strcpy(err_cond, "bad-request");				break;}
		case 480:	{ strcpy(err_cond, "recipient-unavailable");	break;}
		case 481: 	{ strcpy(err_cond, "item-not-found");			break;}
		case 482:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 483:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 484:	{ strcpy(err_cond, "jid-malformed");			break;}
		case 485: 	{ strcpy(err_cond, "item-not-found");			break;}
		case 488:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 491:	{ strcpy(err_cond, "unexpected-request");		break;}
		case 500:   { strcpy(err_cond, "internal-server-error");	break;}
		case 501:   { strcpy(err_cond, "feature-not-implemented");	break;}
		case 502:   { strcpy(err_cond, "remote-server-not-found");	break;}
		case 503:   { strcpy(err_cond, "service-unavailable");		break;}
		case 504:   { strcpy(err_cond, "remote-server-timeout");	break;}
		case 505:	{ strcpy(err_cond, "not-acceptable");			break;}
		case 513:   { strcpy(err_cond, "bad-request");				break;}
		case 600:	{ strcpy(err_cond, "service-unavailable");		break;}
		case 603:	{ strcpy(err_cond, "service-unavailable");		break;}
		case 604:   { strcpy(err_cond, "item-not-found");			break;}
		case 606:	{ strcpy(err_cond, "not-acceptable");			break;}
		default:	{ strcpy(err_cond, "not-acceptable");			break;}
	}

	return err_cond;
}


int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg)
{
	/* named according to the direction of the message in xmpp*/
	str from_uri;
	str to_uri;
	xmlDocPtr doc= NULL;
	xmlNodePtr root_node= NULL, node = NULL;
	xmlAttrPtr attr= NULL;
	str xmpp_msg;
	int code;
	str reason;
	char* err_reason= NULL;
	xmlBufferPtr buffer= NULL;
	char buf_to[256];

	LM_DBG("*** Entered the callback\n");

	URI_ADD_NULL_TERM(to_uri, buf_to, hentity->watcher_uri);
 	from_uri.s = xmpp_uri_sip2xmpp(hentity->pres_uri);
	if(from_uri.s == NULL)
	{
		LM_ERR("Failed to traslate sip uri to xmpp uri\n");
		return -1;
	}
	from_uri.len= strlen(from_uri.s);

	doc= xmlNewDoc(BAD_CAST "1.0");
	if(doc==0)
		goto error;

	root_node = xmlNewNode(NULL, BAD_CAST "presence");

	if(root_node==0)
		goto error;
    	xmlDocSetRootElement(doc, root_node);

	attr= xmlNewProp(root_node, BAD_CAST "to", BAD_CAST to_uri.s);
	if(attr== NULL)
	{
		LM_ERR("while adding attribute to\n");
		goto error;
	}
	attr= xmlNewProp(root_node, BAD_CAST "from", BAD_CAST from_uri.s);
	if(attr== NULL)
	{
		LM_ERR("while adding attribute from\n");
		goto error;
	}

	if(msg== FAKED_REPLY)
	{
		code = 408;
		reason.s= "Request Timeout";
		reason.len= strlen(reason.s)- 1;
	}
	else
	{
		code= msg->first_line.u.reply.statuscode;
		reason= msg->first_line.u.reply.reason;
	}

	LM_DBG("SIP reply code=%d ; to_uri= %s ; from_uri= %s\n",
			code, to_uri.s, from_uri.s);

	if(code>=300)
	{
		err_reason= get_error_reason(code, &reason);
		if(err_reason== NULL)
		{
			LM_ERR("couldn't get response phrase\n");
			goto error;
		}

		attr= xmlNewProp(root_node, BAD_CAST "type", BAD_CAST "error");
		if(attr== NULL)
		{
			LM_ERR("while adding new attribute\n");
			goto error;
		}
		node= xmlNewChild(root_node, 0, BAD_CAST  "error", 0 );
		if(node== NULL)
		{
			LM_ERR("while adding new node\n");
			goto error;
		}
		node= xmlNewChild(node, 0,  BAD_CAST err_reason, 0 );
		if(node== NULL)
		{
			LM_ERR("while adding new node\n");
			goto error;
		}

		attr= xmlNewProp(node, BAD_CAST "xmlns",
				BAD_CAST "urn:ietf:params:xml:ns:xmpp-stanzas");
		if(attr== NULL)
		{
			LM_ERR("while adding new attribute\n");
			goto error;
		}
	}
	else
	{
		if(code>=200 )
		{
			attr= xmlNewProp(root_node, BAD_CAST "type", BAD_CAST "subscribed");
			if(attr== NULL)
			{
				LM_ERR("while adding new attribute\n");
				goto error;
			}
		}
	}

	buffer= xmlBufferCreate();
	if(buffer== NULL)
	{
		LM_ERR("while adding creating new buffer\n");
		goto error;
	}

	xmpp_msg.len= xmlNodeDump(buffer, doc, root_node, 1,1);
	if(xmpp_msg.len== -1)
	{
		LM_ERR("while dumping node\n");
		goto error;
	}
	xmpp_msg.s= (char*)xmlBufferContent( buffer);
	if(xmpp_msg.s==  NULL)
	{
		LM_ERR("while extracting buffer content\n");
		goto error;
	}


	LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s);

	if(xmpp_packet(&from_uri, &to_uri, &xmpp_msg, &hentity->to_tag)< 0)
	{
		LM_ERR("while sending xmpp_reply_to_subscribe\n");
		goto error;
	}
	if(err_reason)
		pkg_free(err_reason);
	xmlFreeDoc(doc);

	return 0;

error:

	if(doc)
		xmlFreeDoc(doc);
	if(err_reason)
		pkg_free(err_reason);
	return -1;

}

