/*
 * callbacks.c
 * 
 * Copyright (C) 2006  Josef Kufner <jk@myserver.cz>
 * 
 * This program 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.
 *
 * This program 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.
 *
 */

#include <stdlib.h>
#include <string.h>

#include "callbacks.h"

#define DEBUG 0
#include "debug.h"


gboolean stdin_data_cb(GIOChannel *source, GIOCondition condition, gpointer data)
{
	GIOStatus ret;
	GError *err = NULL;
	const int msg_size = 1024;
	char msg[msg_size];
	gsize len;

	print_msg(D_DEBUG, "stdin_data_cb...");
	
	if (condition & G_IO_IN) {
		/* read data */
		ret = g_io_channel_read_chars (source, msg, msg_size - 1, &len, &err);
		msg[len] = 0;
		if (ret == G_IO_STATUS_ERROR) {
			print_msg(D_DEBUG, "reading: %s", err->message);
			g_main_loop_quit(main_loop);
			return 0;
		}

		/* send message */
		print_msg(D_DEBUG, "Read %u bytes: %s", len, msg);
		process_stdin(msg, connection);
	}
		
	/* check EOF and HUP */
	if (condition & G_IO_HUP || condition & G_IO_ERR) {
		/* check EOF */
		if (ret == G_IO_STATUS_EOF) {
			print_msg(D_VERBOSE, "EOF from stdin.");
			g_main_loop_quit(main_loop);
			return 0;
		}

	}

	/* bye */
	return 1;
}


void connection_open_cb(LmConnection *connection, gboolean success, gpointer user_data)
{
	if (success) {
		gchar *user;

		/* connected -- send authentication */
		user = get_part_name(j_username);
		if (!lm_connection_authenticate(connection, user, j_password, j_resource, connection_auth_cb, NULL, FALSE, NULL)) {
			g_free(user);
			print_msg(D_ERR, "Failed to send authentication!");
			g_main_loop_quit(main_loop);
			return;
		}
		g_free(user);

		print_msg(D_VERBOSE, "Sent authentication message.");
	} else {
		/* connection failed */
		print_msg(D_ERR, "Failed to connect!");
		g_main_loop_quit(main_loop);
	}
}


LmSSLResponse ssl_cb(LmSSL *ssl, LmSSLStatus status, gpointer ud)
{
	print_msg(D_DEBUG, "SSL status: %d", status);

	switch (status) {
		case LM_SSL_STATUS_NO_CERT_FOUND:
			print_msg(D_ERR, "No certificate found!");
			break;
		case LM_SSL_STATUS_UNTRUSTED_CERT:
			print_msg(D_ERR, "Certificate is not trusted!");
			break;
		case LM_SSL_STATUS_CERT_EXPIRED:
			print_msg(D_ERR, "Certificate has expired!");
			break;
		case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
			print_msg(D_ERR, "Certificate has not been activated!");
			break;
		case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
			print_msg(D_ERR, "Certificate hostname does not match expected hostname!");
			break;
		case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH:
			{
				const gchar *fpr = lm_ssl_get_fingerprint(ssl);
				gchar *str;
				print_msg(D_ERR, "Certificate fingerprint does not match expected fingerprint!");
				str = print_finger(fpr, 16);
				print_msg(D_ERR, "Remote fingerprint:    %s", str);
				g_free(str);
				str = print_finger(expected_fingerprint, 16);
				print_msg(D_ERR, "Expected fingerprint:  %s", str);
				g_free(str);
				break;
			}
		case LM_SSL_STATUS_GENERIC_ERROR:
			print_msg(D_ERR, "Generic SSL error!");
			break;
	}

	if (!j_lax_ssl)
		exit(1);

	return LM_SSL_RESPONSE_CONTINUE;
}


void connection_auth_cb(LmConnection *connection, gboolean success, gpointer user_data)
{
	MESSAGE *msg = NULL;
	
	if (success) {
		GError *error = NULL;
		LmMessage *m;
		LmMessageNode *muc_node, *hist_node;

		print_msg(D_VERBOSE, "Authenticated successfully.");

		/* send initial presence */
		/*
		m = lm_message_new(NULL, LM_MESSAGE_TYPE_PRESENCE);
		if (!lm_connection_send(connection, m, &error)) {
			print_msg(D_ERR, "Failed to send initial presence: '%s'", lm_message_node_to_string(m->node));
		} else {
			print_msg(D_VERBOSE, "Sent initial presence message.");
		}
		lm_message_unref(m);
		*/

		/* send presence to MUC */
		m = lm_message_new(NULL, LM_MESSAGE_TYPE_PRESENCE);
		lm_message_node_set_attribute(m->node, "from", j_from_complete);
		lm_message_node_set_attribute(m->node, "to", j_room_complete);
		lm_message_node_add_child(m->node, "show", "online");
		lm_message_node_add_child(m->node, "status", "");
		muc_node = lm_message_node_add_child(m->node, "x", NULL);
		lm_message_node_set_attribute(muc_node, "xmlns", "http://jabber.org/protocol/muc");
		hist_node = lm_message_node_add_child(muc_node, "history", NULL);
		lm_message_node_set_attribute(hist_node, "since", "20070218T18:43:30");
		if (j_room_passwd) {
			lm_message_node_add_child(muc_node, "password", j_room_passwd);
		}
		if (!lm_connection_send(connection, m, &error)) {
			print_msg(D_ERR, "Failed to send MUC presence: '%s'", lm_message_node_to_string(m->node));
			exit(EXIT_FAILURE);
		} else {
			print_msg(D_VERBOSE, "Sent MUC presence message: '%s'", lm_message_node_to_string(m->node));
		}
		lm_message_unref(m);
		lm_message_node_unref(muc_node);
		lm_message_node_unref(hist_node);

		/* send notification to GUI */
		msg = message_create('N', 'S');
		message_append(msg, MESSAGE_PART_DATA, MESSAGE_STRING, "Son", MESSAGE_STRING, j_room_complete, MESSAGE_END);
		message_to_file(msg, stdout, 0);
		message_destroy(msg);
		
		print_msg(D_NORMAL, "Initialization complete.");
	} else {
		print_msg(D_ERR, "Failed to authenticate!");
	}
}


LmHandlerResult connection_presence_cb (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer user_data)
{
	LmMessageNode *error = NULL;
	MESSAGE *msg;
	const gchar *from, *type;
	char *nick;
	int player_quit;
	
	/* presence received -- show it */
	print_msg(D_VERBOSE, "Received Presence: %s", lm_message_node_to_string(message->node));

	/* check for errors */
	error = lm_message_node_get_child(message->node, "error");
	if (error) {
		print_msg(D_ERR, "Error received: %s (code %s)",
				lm_message_node_get_value(error),
				lm_message_node_get_attribute(error, "code"));
		lm_message_node_unref(error);
		/* TODO */
		exit(EXIT_FAILURE);
	}
		
	/* do something */
	from = lm_message_node_get_attribute(message->node, "from");
	type = lm_message_node_get_attribute(message->node, "type");

	if (from) {
		player_quit = type && strcmp(type, "unavailable") == 0;
		
		/* player join/part info */
		msg = message_create('N', 'S');
		message_append(msg, MESSAGE_PART_DATA, MESSAGE_STRING, player_quit ? "Pp":"Pj",
				MESSAGE_STRING, from,
				MESSAGE_END);
		message_to_file(msg, stdout, 0);
		message_destroy(msg);
		
		if (!player_quit && (nick = strchr(from, '/'))) {
			nick++;
			
			msg = message_create('N', 'S');
			message_append(msg, MESSAGE_PART_DATA, MESSAGE_STRING, "Pn",
					MESSAGE_STRING, from,
					MESSAGE_STRING, nick,
					MESSAGE_END);
			message_to_file(msg, stdout, 0);
			message_destroy(msg);
		}
	}
	

	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}


LmHandlerResult connection_message_cb (LmMessageHandler *handler, LmConnection *connection, LmMessage *message, gpointer user_data)
{
	LmMessageNode *error = NULL, *x = NULL;

	/* message received -- show it */
	print_msg(D_VERBOSE, "Received Message: %s", lm_message_node_to_string(message->node));

	error = lm_message_node_get_child(message->node, "error");

	if (error) {
		print_msg(D_ERR, "Error received: %s (code %s)",
				lm_message_node_get_value(error),
				lm_message_node_get_attribute(error, "code"));
		lm_message_node_unref(error);
		/* TODO */
		exit(EXIT_FAILURE);
	} else {
		x = lm_message_node_get_child(message->node, "x");
		if (!x || (strcmp(lm_message_node_get_attribute(x, "xmlns"), "jabber:x:delay") == 0
				&& strcmp(start_time, lm_message_node_get_attribute(x, "stamp"))) < 0)
		{
			process_message(message, 0);
		} else {
			print_msg(D_DEBUG, "Message is old.")
			process_message(message, 1);
		}
	}

	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}

