/*
 * Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
 * Copyright 2003 Rob Jackson <jacko@xms.ms>
 * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
 *
 * This file is part of NetSurf, http://www.netsurf-browser.org/
 *
 * NetSurf 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; version 2 of the License.
 *
 * NetSurf 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, see <http://www.gnu.org/licenses/>.
 */

/**
 * \file
 * ANT URL launching protocol implementation.
 *
 * See http://www.vigay.com/inet/inet_url.html
 */

#include "utils/config.h"

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <oslib/inetsuite.h>
#include <oslib/wimp.h>

#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/config.h"
#include "content/fetch.h"
#include "netsurf/browser_window.h"

#include "riscos/gui.h"
#include "riscos/uri.h"
#include "riscos/url_protocol.h"

/**
 * Handle a Message_InetSuiteOpenURL.
 */

void ro_url_message_received(wimp_message *message)
{
	char *url;
	int i;
	inetsuite_message_open_url *url_message =
			(inetsuite_message_open_url*) &message->data;
	os_error *error;
	nsurl *nsurl;
	nserror errorns;

	/* If the url_message->indirect.tag is non-zero,
	 * then the message data is contained within the message block.
	 */
	if (url_message->indirect.tag != 0) {
		url = strndup(url_message->url, 236);
		if (!url) {
			ro_warn_user("NoMemory", 0);
			return;
		}
		/* terminate at first control character */
		for (i = 0; !iscntrl(url[i]); i++)
			;
		url[i] = 0;

	} else {
		if (!url_message->indirect.url.offset) {
			NSLOG(netsurf, INFO, "no URL in message");
			return;
		}
		if (28 < message->size &&
				url_message->indirect.body_file.offset) {
			NSLOG(netsurf, INFO,
			      "POST for URL message not implemented");
			return;
		}
		if (url_message->indirect.url.offset < 28 ||
				236 <= url_message->indirect.url.offset) {
			NSLOG(netsurf, INFO,
			      "external pointers in URL message unimplemented");
			/* these messages have never been seen in the wild,
			 * and there is the problem of invalid addresses which
			 * would cause an abort */
			return;
		}

		url = strndup((char *) url_message +
				url_message->indirect.url.offset,
				236 - url_message->indirect.url.offset);
		if (!url) {
			ro_warn_user("NoMemory", 0);
			return;
		}
		for (i = 0; !iscntrl(url[i]); i++)
			;
		url[i] = 0;
	}

	if (nsurl_create(url, &nsurl) != NSERROR_OK) {
		free(url);
		return;
	}

	if (!fetch_can_fetch(nsurl)) {
		nsurl_unref(nsurl);
		free(url);
		return;
	}

	free(url);

	/* send ack */
	message->your_ref = message->my_ref;
	error = xwimp_send_message(wimp_USER_MESSAGE_ACKNOWLEDGE, message,
			message->sender);
	if (error) {
		NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
		      error->errnum, error->errmess);
		ro_warn_user("WimpError", error->errmess);
	}

	/* create new browser window */
	errorns = browser_window_create(BW_CREATE_HISTORY,
				      nsurl,
				      NULL,
				      NULL,
				      NULL);


	nsurl_unref(nsurl);
	if (errorns != NSERROR_OK) {
		ro_warn_user(messages_get_errorcode(errorns), 0);
	}
}


/**
 * Broadcast an ANT URL message.
 */

void ro_url_broadcast(const char *url)
{
	inetsuite_full_message_open_url_direct message;
	os_error *error;
	int len = strlen(url) + 1;

	/* If URL is too long, then forget ANT and try URI, instead */
	if (236 < len) {
		ro_uri_launch(url);
		return;
	}

	message.size = ((20+len+3) & ~3);
	message.your_ref = 0;
	message.action = message_INET_SUITE_OPEN_URL;
	strncpy(message.url, url, 235);
	message.url[235] = 0;
	error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED,
			(wimp_message *) &message, 0);
	if (error) {
		NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
		      error->errnum, error->errmess);
		ro_warn_user("WimpError", error->errmess);
	}
}


/**
 * Launch a program to handle an URL, using the ANT protocol
 * Alias$URLOpen_ system.
 */

void ro_url_load(const char *url)
{
	char *command;
	char *colon;
	os_error *error;

	colon = strchr(url, ':');
	if (!colon) {
		NSLOG(netsurf, INFO, "invalid url '%s'", url);
		return;
	}

	command = malloc(40 + (colon - url) + strlen(url));
	if (!command) {
		ro_warn_user("NoMemory", 0);
		return;
	}

	sprintf(command, "Alias$URLOpen_%.*s", (int) (colon - url), url);
	if (!getenv(command)) {
		free(command);
		return;
	}

	sprintf(command, "URLOpen_%.*s %s", (int) (colon - url), url, url);

	error = xwimp_start_task(command, 0);
	if (error) {
		NSLOG(netsurf, INFO, "xwimp_start_task: 0x%x: %s",
		      error->errnum, error->errmess);
		ro_warn_user("WimpError", error->errmess);
	}

	free(command);
}


/**
 * Handle a bounced Message_InetSuiteOpenURL.
 */

void ro_url_bounce(wimp_message *message)
{
	inetsuite_message_open_url *url_message =
			(inetsuite_message_open_url*) &message->data;

	/* ant broadcast bounced -> try uri broadcast / load */
	ro_uri_launch(url_message->url);
}

