/*-
 * $Id: rr-greeting.c,v 1.24 2002/11/08 12:35:28 jonas Exp $
 *
 * See the file LICENSE for redistribution information. 
 * If you have not received a copy of the license, please contact CodeFactory
 * by email at info@codefactory.se, or on the web at http://www.codefactory.se/
 * You may also write to: CodeFactory AB, SE-903 47, Umeå, Sweden.
 *
 * Copyright (c) 2002 Jonas Borgström <jonas@codefactory.se>
 * Copyright (c) 2002 Daniel Lundin   <daniel@codefactory.se>
 * Copyright (c) 2002 CodeFactory AB.  All rights reserved.
 */

#include <librr/rr.h>

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include <string.h>

static GObjectClass *parent_class = NULL;

static RRFrame *get_frame (RRMessage *msg, gsize max_size);
static gboolean process_frame (RRMessage *msg, RRFrame *frame, GError **err);

static void finalize (GObject *object);

static void
rr_greeting_init (GObject *object)
{
	RRMessage *msg = (RRMessage *)object;

	msg->type = RR_FRAME_TYPE_RPY;
}

static void
rr_greeting_class_init (GObjectClass *klass)
{
	RRMessageClass *msg_class = (RRMessageClass *)klass;

	klass->finalize = finalize;

	msg_class->get_frame = get_frame;
	msg_class->process_frame = process_frame;

	parent_class = g_type_class_peek_parent (klass);
}

GType 
rr_greeting_get_type (void)
{
	static GType rr_type = 0;

	if (!rr_type) {
		static GTypeInfo type_info = {
			sizeof (RRGreetingClass),
			NULL,
			NULL,
			(GClassInitFunc) rr_greeting_class_init,
			NULL,
			NULL,
			sizeof (RRGreeting),
			16,
			(GInstanceInitFunc) rr_greeting_init
		};
		rr_type = g_type_register_static (RR_TYPE_MESSAGE, "RRGreeting", 
						  &type_info, 0);
	}
	return rr_type;
}


static void
finalize (GObject *object)
{
	RRGreeting *greeting = (RRGreeting *)object;
	
	if (greeting->localize)
		g_free (greeting->localize);

	if (greeting->features)
		g_free (greeting->features);

	g_slist_foreach (greeting->peer_profiles, (GFunc)g_free, NULL);
	g_slist_free (greeting->peer_profiles);

	parent_class->finalize (object);
}


RRGreeting *
rr_greeting_new (RRProfileRegistry *profreg, const gchar *localize, 
		 const gchar *features)
{
	RRGreeting *greeting;

	greeting = g_object_new (RR_TYPE_GREETING, NULL);

	greeting->profreg = profreg;
	if (localize)
		greeting->localize = g_strdup (localize);
	if (features)
		greeting->features = g_strdup (features);

	return greeting;
}


static void
hash_profiles_greeting_str (gpointer key, gpointer value, gpointer user_data)
{
	GString *buf = (GString *)user_data;
	gchar *uri = (gchar *)key;

	g_string_append_printf (buf, "   <profile uri='%s' />\r\n", uri);
}

static gboolean
process_frame (RRMessage *message, RRFrame *frame, GError **error)
{
	RRGreeting *greeting;
	RRConnection *conn;
	xmlDocPtr doc;
	xmlNodePtr node;
	gboolean ret;
	const gchar *data;
	gint len;

	g_return_val_if_fail (RR_IS_GREETING (message), FALSE);
	g_return_val_if_fail (RR_IS_FRAME (frame), FALSE);
	g_return_val_if_fail (RR_IS_CHANNEL (message->channel), FALSE);
	g_return_val_if_fail (RR_IS_CONNECTION (message->channel->connection), 
			      FALSE);

	conn = message->channel->connection;
	greeting = RR_GREETING (message);

	data = rr_frame_mime_get_body (frame);
	len  = rr_frame_mime_get_body_size (frame);

	doc = xmlParseMemory (data, len);
	if (doc == NULL) {
		g_set_error (error, RR_ERROR, RR_BEEP_CODE_SYNTAX_ERROR, 
			     "Invalid greeting message.");
		return FALSE;
	}

	node = xmlDocGetRootElement (doc);

	if (strcmp (node->name, "greeting") != 0)
		goto err;

	node = node->children;

	while (node) {
		xmlChar *str;
		gchar *uri;

		/* Ignore none element nodes */
		while (node && node->type != XML_ELEMENT_NODE)
			node = node->next;
		if (node == NULL)
			break;

		if (strcmp (node->name, "profile") != 0)
			goto err;

		if ((str = xmlGetProp (node, "uri")) == NULL)
			goto err;

		uri = g_strdup (str);
		xmlFree (str);

		greeting->peer_profiles = g_slist_append (greeting->peer_profiles,
							  uri);
		node = node->next;
	}
	ret = TRUE;
	goto end;
 err:
	g_set_error (error, RR_ERROR, RR_BEEP_CODE_PARAM_ERROR, RR_GERROR_DEFAULT_MESSAGE); 
	ret = FALSE;
 end:
	xmlFreeDoc (doc);

	return ret;
}

static RRFrame *
get_frame (RRMessage *msg, gsize max_size)
{
	RRGreeting *greeting = (RRGreeting *)msg;
	RRProfileRegistry *profreg;
	RRFrame *frame;
	GString *greetingstr;
	GString *profilestr;

	g_return_val_if_fail (RR_IS_GREETING (greeting), NULL);

	greetingstr = g_string_new (RR_BEEP_MIME_HEADER);
	profilestr = g_string_new (NULL);

	profreg = greeting->profreg;
	if (profreg && RR_IS_PROFILE_REGISTRY (profreg)) {
		g_static_rw_lock_reader_lock (&(profreg->rwlock));
		g_hash_table_foreach (profreg->profiles_by_uri,
				      hash_profiles_greeting_str,
				      profilestr);
		g_static_rw_lock_reader_unlock (&(profreg->rwlock));
	} else {
		g_print ("greeting.get_frame: There is no profile registry. "
			 "How strange...\n");
	}
	g_string_append (greetingstr, "<greeting");
	if (greeting->localize) {
		g_string_append_printf (greetingstr, " localize=\"%s\"", 
					greeting->localize);
	}
	if (greeting->features) {
		g_string_append_printf (greetingstr, " features=\"%s\"", 
					greeting->features);
	}
	if (profilestr->len > 0) {
		g_string_append_printf (greetingstr, 
					">\r\n%s</greeting>\r\n",
					profilestr->str);
	} else {
		g_string_append (greetingstr, " />\r\n");
	}

	if (max_size < greetingstr->len) {

		g_string_free (greetingstr, TRUE); 
		g_string_free (profilestr, TRUE);
		return NULL;
	}
	frame = rr_frame_new (RR_FRAME_TYPE_RPY, msg->channel->id, FALSE, 
			      msg->msgno,
			      greetingstr->len, 0, 
			      greetingstr->str, TRUE);

	g_string_free (greetingstr, FALSE); /* Note: The string data is
					       referenced in the frame  */
	g_string_free (profilestr, TRUE);

	return frame;
}



syntax highlighted by Code2HTML, v. 0.9.1