/*
 * pua_xmpp module - presence SIP - XMPP Gateway
 *
 * Copyright (C) 2007 Voice Sistem S.R.L.
 *
 * This file is part of Kamailio, a free SIP server.
 *
 * Kamailio 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
 *
 * Kamailio 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
 *
 */

/*! \file
 * \brief Kamailio presence gateway: SIP/SIMPLE -- XMPP (pua_xmpp)
 */

#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>

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

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, TO = {0}, *pfrom = NULL;
	str to_uri;
	char* uri= NULL;
	str from_uri;
	struct hdr_field* hdr= NULL;
	str body;
	int is_terminated= 0;
	str id;
	ua_pres_t dialog;
	int event_flag= 0;

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

	LM_DBG("start...\n\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;
	}

	if(msg->to->parsed != NULL)
	{
		pto = (struct to_body*)msg->to->parsed;
		LM_DBG("'To' header ALREADY PARSED:<%.*s>\n",pto->uri.len,pto->uri.s);
	}
	else
	{
		parse_to(msg->to->body.s,msg->to->body.s + msg->to->body.len + 1, &TO);
		if(TO.uri.len <= 0)
		{
			LM_ERR("'To' header NOT parsed\n");
			goto error;
		}
		pto = &TO;
	}

	dialog.watcher_uri= &pto->uri;

	uri=(char*)pkg_malloc(sizeof(char)*( pto->uri.len+1));
	if(uri== NULL)
	{
		LM_ERR("no more memory\n");
		goto error;
	}
	memcpy(uri, pto->uri.s, pto->uri.len);
	uri[pto->uri.len]= '\0';
	to_uri.s= duri_sip_xmpp(uri);
	if(to_uri.s== NULL)
	{
		LM_ERR("while decoding sip uri in xmpp\n");
		pkg_free(uri);
		goto error;
	}
	to_uri.len= strlen(to_uri.s);
	pkg_free(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)
	{
		LM_ERR("'From' header not parsed\n");
		/* 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;

	uri=(char*)pkg_malloc(sizeof(char)*( pfrom->uri.len+1));
	if(uri== NULL)
	{
		LM_ERR("no more memory\n");
		goto error;
	}
	memcpy(uri, pfrom->uri.s, pfrom->uri.len);
	uri[pfrom->uri.len]= '\0';

	from_uri.s= euri_sip_xmpp(uri);
	if(from_uri.s== NULL)
	{
		LM_ERR("while encoding sip uri in xmpp\n");
		pkg_free(uri);
		goto error;
	}
	from_uri.len= strlen(from_uri.s);
	pkg_free(uri);

	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 &&
			(strncmp(msg->event->body.s,"presence",8 )==0))
		event_flag|= PRESENCE_EVENT;
	else
		if(msg->event->body.len== 14 &&
				(strncmp(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
	{
		body.s=get_body(msg);
		if (body.s== NULL)
		{
			LM_ERR("cannot extract body from msg\n");
			goto error;
		}
		body.len = get_content_length( msg );
	}

	/* treat the two cases: event= presence & event=presence.winfo */
	if(event_flag & PRESENCE_EVENT)
	{
		LM_DBG("PRESENCE\n");
		hdr = msg->headers;
		while (hdr!= NULL)
		{
			if(cmp_hdrname_strzn(&hdr->name, "Subscription-State", 18)==0)
				break;
			hdr = hdr->next;
		}
		if(hdr && strncmp(hdr->body.s,"terminated", 10)== 0)
		{
			/* chack if reason timeout => don't send notification */
			if(strncmp(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 = msg->headers;
			while (hdr!= NULL)
			{
				if(cmp_hdrname_strzn(&hdr->name, "Subscription-State", 18)==0)
					break;
				hdr = hdr->next;
			}
			if(hdr && strncmp(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;
		}

	}
	free_to_params(&TO);
	return 1;

error:
	free_to_params(&TO);
	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)||
			(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"On the phone")== 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;
			}
		}
		else
			if((xmlStrcasecmp((unsigned char*)note,
							(unsigned char*)"dnd")== 0)||
					(xmlStrcasecmp((unsigned char*)note,
								(unsigned char*)"do not disturb")== 0)||
					(xmlStrcasecmp((unsigned char*)note,
								(unsigned char*)"Busy (DND)")== 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;
				}
			}
			else
				LM_DBG("Not Found Status\n");


	/* 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(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;
	xmlDocPtr notify_doc= NULL;
	xmlDocPtr doc= NULL;
	xmlNodePtr pidf_root= NULL;
	xmlNodePtr root_node= NULL;
	xmlNodePtr node= NULL;
	xmlBufferPtr buffer= NULL;

	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;
		}
		from_uri.s= euri_sip_xmpp(watcher);
		if(from_uri.s== NULL)
		{
			LM_ERR("while encoding sip uri in 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)
{
	char* uri;
	/* 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;

	LM_DBG("start..\n");
	uri=(char*)pkg_malloc(sizeof(char)*( hentity->watcher_uri->len+1));
	if(uri== NULL)
	{
		LM_ERR("no more memory\n");
		goto error;
	}
	memcpy(uri, hentity->watcher_uri->s, hentity->watcher_uri->len);
	uri[hentity->watcher_uri->len]= '\0';
	to_uri.s= duri_sip_xmpp(uri);
	if(to_uri.s== NULL)
	{
		LM_ERR("whil decoding sip uri in xmpp\n");
		pkg_free(uri);
		goto error;
	}

	to_uri.len= strlen(to_uri.s);
	pkg_free(uri);

	uri=(char*)pkg_malloc(sizeof(char)*( hentity->pres_uri->len+1));
	if(uri== NULL)
	{
		LM_ERR("no more memory\n");
		goto error;
	}
	memcpy(uri, hentity->pres_uri->s, hentity->pres_uri->len);
	uri[hentity->pres_uri->len]= '\0';
	from_uri.s= euri_sip_xmpp(uri);
	if(from_uri.s== NULL)
	{
		LM_ERR("while encoding sip uri in xmpp\n");
		pkg_free(uri);
		goto error;
	}

	from_uri.len= strlen(from_uri.s);
	pkg_free(uri);

	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(" to_uri= %s\n\t from_uri= %s\n",
			to_uri.s, from_uri.s);

	if(code>=300)
	{
		LM_DBG(" error code(>= 300)\n");
		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 )
		{
			LM_DBG(" 2xx code\n");
			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;

}

