/* Bluefish HTML Editor
 * network.c - Open from Web
 *
 * Copyright (C) 1999 Neil Millar
 *
 * 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.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * To add:      Catch errors
 *                      Redirection
 */
#include "default_include.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <strings.h> /* for Solaris bzero() ? */
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "bluefish.h"
#include "interface.h"
#include "network.h"
#include "document.h"

/* again extern ? TRY TO AVOID EXTERN DEFINITIONS IN .C FILES!!!!
USE #INCLUDE STATEMENTS INSTEAD!!!
 */

extern void file_close(GtkWidget * widget, gpointer data);

gint port = 80;
gint sockfd;
gint closed = 0;

gint open_web(gchar * address)
{
#ifndef WIN32
	gchar *server;
	gchar *ip_address;
	gchar *page_location;
	gchar *status_string;
	gchar *temp_ptr;
	gint num_bytes;
	gint first_time = 0;
	gint doc_size = 0;
	gint going = 0;
	gint received;
	gchar buf[1024];
	gchar temp_buf[1024];
	gchar send_buf[512];
	struct sockaddr_in their_addr;

	server = extract_address(address);
	if (server == "secure")
		return 1;
	else if (server == "undefined")
		return 2;

	page_location = extract_filename(address, server);
	DEBUG_MSG("open_web, Page location is %s\n", page_location);
	if (page_location == NULL) {
		page_location = g_malloc0(16);
		sprintf(page_location, "/");
	}

	statusbar_message(_("Resolving address"), 1000);
	ip_address = resolve(server);
	flush_queue();
	if (ip_address == "1")
		return 3;
	DEBUG_MSG("open_web, IP address of %s is %s\n", server, ip_address);
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		return 4;

/*
 *  Even if we identify ourselves as HTTP 1.0 compliant (Yeah right!),
 *      servers still need the Host: for multiple names per IP
 *      e.g. www.millar.u-net.com :) 
 */

	sprintf(send_buf, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost:%s\r\n\r\n", page_location, CURRENT_VERSION_NAME, server);
	their_addr.sin_family = AF_INET;
	their_addr.sin_port = htons(port);
	their_addr.sin_addr.s_addr = inet_addr(ip_address);
	bzero(&(their_addr.sin_zero), 8);
	if (connect(sockfd, (struct sockaddr *) &their_addr, sizeof(struct sockaddr))
		== -1)
		return 5;
	DEBUG_MSG("open_web, Connected\n");
	num_bytes = send(sockfd, send_buf, strlen(send_buf), 0);

	if (num_bytes == -1)
		return 6;
	else if (num_bytes != strlen(send_buf))
		return 7;

	bzero(buf, 1024);
	DEBUG_MSG("open_web, Sent: %s\n", send_buf);

	if ((main_v->current_document->filename == NULL && main_v->current_document->modified ==
		 FALSE && g_list_length(main_v->documentlist) == 2)) {
		DEBUG_MSG("open_web, no new document created\n");
	} else {
		main_v->current_document = doc_new();
		DEBUG_MSG("open_web, new document created\n");
	}
	gtk_text_freeze(GTK_TEXT(main_v->current_document->textbox));
	statusbar_message(_("Retrieving file, press ESC to cancel download"), 1000);
/* Re-using num_bytes for the number of received bytes */
	status_string = g_malloc0(200);
	num_bytes = 0;

	/* make the socket non-blocking so we can call flush_queue() 
	   when there is no data.
	   If you don't call flush_queue() a key_press event (ESC) will
	   not stop the download since the whole program (including
	   gtk_main() will be blocked until there is some data on the 
	   filedescriptor again
	 */
	fcntl(sockfd, F_SETFL, O_NONBLOCK);

	going = 1;
	while (going) {
		received = recvfrom(sockfd, buf, 1023, 0, NULL, 0);
		if (received == 0) {
			DEBUG_MSG("open_web, received=%d --> end of file\n", received);
			going = 0;
		} else if (received == -1) {

			/* check the gtk and gdk events (ESC pressed?) */
			flush_queue();
			/* Has the user cancelled the d/l? */
			if (closed == 1) {
				DEBUG_MSG("open_web, closed=%d, stopping the download\n", closed);
				statusbar_message(_("User aborted download"), 2000);
				closed = 0;
				going = 0;
				return 9;
			}
			DEBUG_MSG("open_web, no data waiting (received=%d) --> sleep\n", received);
			/* do we need the sleep() call here?
			   if we don't cpu usage will probably go up to 100%
			   since the loop will run on flush_queue() till there is
			   some data on the socket again
			 */
#ifndef WIN32
			sleep(1);
#endif
		} else if (received > 0) {
			DEBUG_MSG("open_web, received=%d, >0\n", received);

/* If it's the first loop, check some stuff (Expected doc length etc.) */
			if (first_time == 0) {

/* Do you remember the ... */
				first_time = 1;
/* 302 Error: Relocation */
				temp_ptr = strstr(buf, "Location:");
				if (temp_ptr != NULL) {
					temp_ptr += strlen("Location:");
					strcpy(temp_buf, temp_ptr);
					DEBUG_MSG("open_web, Relocated to: %s\n", temp_buf);
/* Recurses, if it wasn't for those pesky kids */
					/* open_web(temp_buf); */
				}

/* How long is this document supposed to be? */
				temp_ptr = strstr(buf, "Content-Length:");
				if (temp_ptr != NULL) {
					temp_ptr += strlen("Content-Length:");
					doc_size = atoi(temp_ptr);
					DEBUG_MSG("open_web, Got length: %d\n", doc_size);
				}
/* Send all the head_cbers to the bit bucket in the sky */
				bzero(temp_buf, 1024);
				strcpy(temp_buf, buf);
				DEBUG_MSG("open_web, tempbuf %p contains '%s'\n", temp_buf, temp_buf);
				temp_ptr = strstr(temp_buf, "\n\r\n");
				if (!temp_ptr) {
					temp_ptr = strstr(temp_buf, "\n\n");
					if (temp_ptr) {
						temp_ptr += 2;
					}
				} else {
				temp_ptr += 3;
				}
				DEBUG_MSG("open_web, tempptr is found as %p\n", temp_ptr);
				bzero(buf, 1024);
				if (temp_ptr == NULL) {
/* The first < wasn't in this chunk, let's go round again */
					strcpy(buf, "");
					first_time = 0;
				} else {
					strcpy(buf, temp_ptr);
				}
			}

			gtk_text_insert(GTK_TEXT(main_v->current_document->textbox), NULL, NULL, NULL, buf, -1);
			num_bytes = num_bytes + strlen(buf);
			bzero(buf, 1024);

			if (doc_size == 0)
				sprintf(status_string, _("Retrieving file, %d bytes received, press ESC to cancel"), num_bytes);
			else
				sprintf(status_string, _("Retrieving file, %d bytes of %d bytes received, press ESC to cancel"), num_bytes, doc_size);

			statusbar_message(status_string, 1000);
			flush_queue();
		}

	}
	g_free(status_string);

	close(sockfd);
	gtk_text_thaw(GTK_TEXT(main_v->current_document->textbox));
	doc_set_modified(main_v->current_document, 1);
	DEBUG_MSG("open_web, document thawed, end\n");
	return 0;
#else
	return 6;
#endif
}

gint send_email_cb(gchar * address)
{
	/* This space for rent */
	return 0;
}

gchar *resolve(gchar * address)
{
#ifndef WIN32
	struct hostent *h;
	if ((h = gethostbyname(address)) == NULL)
		return "1";

	return inet_ntoa(*(struct in_addr *) h->h_addr_list[0]);
#else
	return "1";
#endif
}

gchar *extract_address(gchar * address)
{
/* Find the name of the server and return string, set global port int */
	gint string_size;
	gchar *begin_ptr;
	gchar *temp_ptr;
	static gchar *return_string;

	return_string = g_malloc0(256);

	if (strlen(address) == 0) {
		return "undefined";
	}

	begin_ptr = &address[0];
	temp_ptr = strstr(address, "http");

	if (temp_ptr != NULL) {
		temp_ptr += 4;
		switch (temp_ptr[0]) {
		case 's':
			return "secure";
			break;
		case ':':
			temp_ptr += 3;
			begin_ptr = temp_ptr;
			break;
		default:
			return "undefined";
		}
	}

/* Check for port number */

	temp_ptr = strchr(begin_ptr, ':');
	if (temp_ptr != NULL) {
/* Could that be? Yes it is! The lesser spotted pointer increment */
		temp_ptr++;
		port = atoi(temp_ptr);
		DEBUG_MSG("extract_address, Got a port: %d\n", port);
		temp_ptr--;
	} else {
		port = 80;
		temp_ptr = strchr(begin_ptr, '/');

/* if no path e.g. www.millar.u-net.com */

		if (temp_ptr == NULL)
			return begin_ptr;
	}

	string_size = strlen(begin_ptr) - strlen(temp_ptr);
	strncat(return_string, begin_ptr, string_size);
	DEBUG_MSG("extract_address, Return string is %s\n", return_string);
	return return_string;
}

gchar *extract_filename(gchar * address, gchar * server)
{
/* Take URL, return file location */
	gchar *temp_ptr;
	gint server_size;

	server_size = strlen(server);
	temp_ptr = address;
	temp_ptr += server_size;

	if (temp_ptr[0] == '/')
		return temp_ptr;
	else {
		address = temp_ptr;
		temp_ptr = strchr(address, '/');
		return temp_ptr;
	}
}
