/*-*-linux-c-*-*/

/*
 *  gnewtellium - Newtella for Unix
 *  Copyright (C) 2001 Elias Athanasopoulos
 *
 *  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
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>

#include <gtk/gtk.h>

#include "global.h"
#include "gnutella.h"
#include "gui.h"
#include "config.h"
#include "newtella.h"

/* General functions for hosts' management. */


int host_is_private_old(guint32 ip, guint16 port)
{
	if (!ip || !port)
		return 1;	/* IP == 0 || Port == 0	*/

	if (ip == (guint32) 0x01020304 || ip == (guint32) 0x01010101)
		return 1;	/* IP == 1.2.3.4 || IP == 1.1.1.1 	*/
	if ((ip & (guint32) 0xFF000000) == (guint32) 0x00000000)
		return 1;	/* IP == 0.0.0.0 / 8		 	*/
	//if ((ip & (guint32) 0xFF000000) == (guint32) 0x7F000000)
	//	return 1;	/* IP == 127.0.0.0 / 8			*/
	if ((ip & (guint32) 0xFF000000) == (guint32) 0x0A000000)
		return 1;	/* IP == 10.0.0.0 / 8			*/
	if ((ip & (guint32) 0xFFF00000) == (guint32) 0xAC100000)
		return 1; 	/* IP == 172.16.0.0 / 12		*/
	if ((ip & (guint32) 0xFFFF0000) == (guint32) 0xC0A80000)
		return 1;	/* IP == 192.168.0.0 / 16		*/

	return 0;
}


int host_is_private(uint8_t *ip, guint16 port)
{
        struct in6_addr in6;
	if (!port)
		return 1;
	memcpy(in6.s6_addr, ip, sizeof(in6.s6_addr));
	if (IN6_IS_ADDR_UNSPECIFIED(&in6))
		return 1;	// IP == ::0
	if (IN6_IS_ADDR_LOOPBACK(&in6))
		return 1;	// IP == ::1
	if (IN6_IS_ADDR_MULTICAST(&in6) && !IN6_IS_ADDR_MC_GLOBAL(&in6))
		return 1;	// Lokale Multicast-Adressen
	if (IN6_IS_ADDR_LINKLOCAL(&in6))
		return 1;	// Linklocal-Adressen
	if (IN6_IS_ADDR_SITELOCAL(&in6))
		return 1;	// Sitelocal-Adressen
	if (IN6_IS_ADDR_V4MAPPED(&in6))
		return 1;	// Kommunikation mit IP4-Host

	return 0;
}

int host_remove(uint8_t *ip, guint16 port)
{
	GList *iter;
	struct host_info *host;
	gchar buf[255];

	iter = g_list_first(gl_hosts_in_cache);

	while (iter) {
		host = iter->data;
		if (memcmp(host->ip, ip, sizeof(host->ip)) == 0 && host->port == port) {
			gl_hosts_in_cache = g_list_remove(gl_hosts_in_cache, host);
			newtella_free(host);
			gl_options->hosts_in_cache--;

			/* gui update */
			g_snprintf(buf, sizeof(buf), "%d", gl_options->hosts_in_cache);
			gtk_label_set_text(GTK_LABEL(host_in_cache_label), buf);
			break;
		}

		iter = g_list_next(iter);
	}

	return 1;
}

int host_add_in_cache(struct gnutella_pong_header *gpong)
{
	GList *iter;
	struct host_info *new_host, *host;
	gchar buf[5];

	/* if it is a private IP the host is useless */
	if (host_is_private(gpong->host_ip, gpong->host_port))
		return -1;

	new_host = newtella_malloc(sizeof(struct host_info));
	bzero(new_host->ip, sizeof(new_host->ip));
	memcpy(new_host->ip, gpong->host_ip, sizeof(new_host->ip));
	new_host->port = gpong->host_port;
	new_host->file_count = gpong->file_count;
	new_host->files_total_size = gpong->files_total_size;
	new_host->used = 0;

	iter = g_list_first(gl_hosts_in_cache);

	/* check if we already have it in cache */
	while (iter) {
		host = iter->data;
		//printf("MEMCMP: %d\n", memcmp(new_host->ip, host->ip,sizeof(new_host->ip)));
		if ((memcmp(new_host->ip, host->ip,sizeof(new_host->ip)) == 0) && (new_host->port == host->port)) {
			// Igor: Hier werden die Daten jetzt aufgefrischt
			if (new_host->file_count != host->file_count)
				host->file_count = new_host->file_count;
			if (new_host->files_total_size != host->files_total_size)
				host->files_total_size = new_host->files_total_size;
			if (new_host->host_name != host->host_name)
				strcpy(host->host_name, new_host->host_name);
			//
			newtella_free(new_host);
			return -1;
		}

		iter = g_list_next(iter);
	}

	gl_hosts_in_cache = g_list_append(gl_hosts_in_cache, new_host);
	gl_options->hosts_in_cache++;

	/* gui update */
	g_snprintf(buf, sizeof(buf), "%d", gl_options->hosts_in_cache);
	gtk_label_set_text(GTK_LABEL(host_in_cache_label), buf);

	return 1;
}

int host_save_cache_to_file(void)
{
	/* save available hosts */
	DIR *cfg_dir;
	FILE *cfg_file;
        gchar *cfg_name = newtella_malloc(255);
	GList *iter;
	struct host_info *a_host;
	gchar ip[INET6_ADDRSTRLEN] = "\0";

        strcpy(cfg_name, getenv("HOME"));

        cfg_name = strcat(cfg_name, "/.gnewtellium");

        /* check if dir exist */
        cfg_dir = opendir(cfg_name);
        if (!cfg_dir && errno == ENOENT)
                config_create_dir(cfg_name);

	cfg_name = strcat(cfg_name, "/hosts");

	cfg_file = fopen(cfg_name, "w+");

	if (cfg_file) {
		iter = g_list_first(gl_hosts_in_cache);

		while (iter != NULL) {
			a_host = iter->data;

			memcpy(ip, ip2str(a_host->ip), sizeof(ip));
			fprintf(cfg_file, "%s/%d\n", ip, a_host->port);

			iter = g_list_next(iter);
		}

	}

	fclose(cfg_file);

	return 1;

}

int host_load_cache_from_file(void)
{
	FILE *cfg_file;
        gchar *cfg_name = newtella_malloc(255), *host_port;
        gchar host_entry[255];
	gchar ipstr[INET6_ADDRSTRLEN] = "\0";
	struct gnutella_pong_header *new_host;
	int i;

	strcpy(cfg_name, getenv("HOME"));

        cfg_name = strcat(cfg_name, "/.gnewtellium/hosts");

       	cfg_file = fopen(cfg_name, "r");

	if (!cfg_file)
		return 0;

	while (fgets(host_entry, sizeof(host_entry), cfg_file)) {
		if (host_entry[0] == '#' || host_entry[0] == '\n') continue;
		host_port = host_entry;
                i = 0;
		while (*host_port && *host_port!='/'){
			host_port++;
			i++;
		}

		*host_port++ = 0;

		new_host = newtella_malloc(sizeof(struct gnutella_pong_header));
		memcpy(ipstr, host_entry, i);
		bzero(new_host->host_ip, sizeof(new_host->host_ip));
		memcpy(new_host->host_ip, str2ip(ipstr), sizeof(new_host->host_ip));
		new_host->host_port = atol(host_port);
		host_add_in_cache(new_host);
		newtella_free (new_host);
	}

	fclose(cfg_file);
	return 1;
}
