/*-*-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 "../config.h"
#include "../pixmaps/gnewtellium.xpm"

#include <gtk/gtk.h>

#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>

#include "newtella.h"
#include "global.h"
#include "gui.h"
#include "gnutella.h"
#include "config.h"
#include "file.h"
#include "downloads.h"
#include "uploads.h"
#include "hosts.h"

void gui_add_con_to_list(struct newtella_connection *con)
{
	gchar *dummy[4] = { "", "", "", "" };
	gchar l_ip[255];
	gchar ip[INET6_ADDRSTRLEN] = "\0";


	gint row;
	row = gtk_clist_append(GTK_CLIST(con_list), dummy);

	gtk_clist_set_row_data(GTK_CLIST(con_list), row, (gpointer) con);

	memcpy(ip, ip2str(con->ip), sizeof(ip));
	/* Set IP:Port for each connection in the GUI */
	g_snprintf(l_ip, sizeof(l_ip), "[%s]:%d", ip, con->port);
	gtk_clist_set_text(GTK_CLIST(con_list), row, 0, l_ip);
	gtk_clist_set_text(GTK_CLIST(con_list), row, 2, "0/0");
	gtk_clist_set_text(GTK_CLIST(con_list), row, 3, "0/0/0");

	gl_options->cons++;

	gui_update_con_status(con);
}

void gui_update_con_status(struct newtella_connection *con)
{
	static  guint32 last = 0;
	        guint32 now;
	        gint    row;
                gchar   l_sent[255], l_recv[255];
		GList  *l;
		gint    pending_packets_len = 0;
		struct  gpacket *packet;

	row = gtk_clist_find_row_from_data(GTK_CLIST(con_list), (gpointer) con);

	now = time((time_t)NULL);

	if ((now - last < 1) && (con->total_handled > 50))
		return;
	else
		last = now;

	switch (con->state) {
	case GS_WAITINGCONNECT:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "Connecting...");
		break;
	case GS_HANDSHAKE:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "Handshaking...");
		break;
	case GS_CONNECTED:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "OK");
		break;
	case GS_FAILED:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "Failed");
		break;
	case GS_TIMEOUT:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "Time Out");
		break;
	case GS_HOSTFEED:
		gtk_clist_set_text(GTK_CLIST(con_list), row, 1, "Feeding...");
		break;
	default:
		break;
	}

	for (l = con->queue; l; l = l->next) {
		packet = l->data;
		pending_packets_len += packet->len;
	}

	/* packets received/dropped */
	g_snprintf(l_sent, sizeof(l_sent), "%d/%d (%d:%d)", con->total_sent,
		   con->total_dropped_to_send,
		   g_list_length(con->queue), pending_packets_len);

	g_snprintf(l_recv, sizeof(l_recv), "%d/%d/%d", con->total_handled,
		   con->total_received_dropped, con->total_bad_received);

	gtk_clist_set_text(GTK_CLIST(con_list), row, 2, l_sent);
	gtk_clist_set_text(GTK_CLIST(con_list), row, 3, l_recv);
}

void gui_update_found_results(int id, char *vendor)
{
	GdkColor blue = { 0, 0, 0, 65535 };
	GdkColor gnew = { 0, 65535, 0, 0 };
	GList *iter;
	struct file_found *found;
	gchar buf[255], l_size[255], l_speed[255], l_loc[255] = "Push";
	gint row = id;
	gchar ip[INET6_ADDRSTRLEN] = "\0";

	iter = g_list_nth(gl_results, row);

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

		if (found->size < 1024)
			g_snprintf(l_size, sizeof(l_size), "%u Bytes", found->size);
		else if (found->size < 1048576)
			g_snprintf(l_size, sizeof(l_size), "%.1fKB", (float)found->size/1024.0);
		else if (found->size < 1073741824)
			g_snprintf(l_size, sizeof(l_size), "%.1fMB", (float)found->size/1048576.0);
		else
			g_snprintf(l_size, sizeof(l_size), "%.1fGB", (float)found->size/1073741824.0);

		g_snprintf(l_speed, sizeof(l_speed), "%d", found->speed);

		if (!found->push)
		        memcpy(ip, ip2str(found->ip), sizeof(ip));
			g_snprintf(l_loc, sizeof(l_loc), "%s", ip);

		gtk_clist_set_text(GTK_CLIST(search_list), row, 0, found->file_name);
		gtk_clist_set_text(GTK_CLIST(search_list), row, 1, l_size);
		gtk_clist_set_text(GTK_CLIST(search_list), row, 2, l_speed);
		gtk_clist_set_text(GTK_CLIST(search_list), row, 3, l_loc);
		gtk_clist_set_text(GTK_CLIST(search_list), row, 4, vendor);

		if (!found->busy)
			gtk_clist_set_foreground(GTK_CLIST(search_list), row, &blue);

		if (!strcmp(vendor, "Gnewtellium-IPv6"))
			gtk_clist_set_foreground(GTK_CLIST(search_list), row, &gnew);

		row++;

		iter = g_list_next(iter);
	}

	/* update the found files label */
	g_snprintf(buf, sizeof(buf), "%d", gl_options->files_found);
	gtk_label_set_text(GTK_LABEL(files_found_label), buf);
}

void gui_clean_found_results(void)
{
	GList *iter;
	struct file_found *found;

	iter = g_list_first(gl_results);
	while (iter) {
		found = (struct file_found *) iter->data;

		newtella_free(found->file_name);
		newtella_free(found);

		iter = g_list_next(iter);
	}

	g_list_free(gl_results);

	gtk_clist_clear(GTK_CLIST(search_list));
	gtk_label_set_text(GTK_LABEL(files_found_label), "0");

	gl_options->files_found = 0;
	gl_results = NULL;
}

void gui_add_download(struct newtella_connection *dcon)
{
	gchar *dummy[5] = { "", "", "", "", "" };
	gchar l_size[255], l_status[255], l_speed[255], l_server[255];
	gchar ip[INET6_ADDRSTRLEN] = "\0";
	gint row = gtk_clist_append(GTK_CLIST(download_list), dummy);

	gtk_clist_set_row_data(GTK_CLIST(download_list), row, (gpointer) dcon);

	if (dcon->fi->size < 1024)
		g_snprintf(l_size, sizeof(l_size), "%u Bytes", dcon->fi->size);
	else if (dcon->fi->size < 1048576)
		g_snprintf(l_size, sizeof(l_size), "%.1fKB", (float)dcon->fi->size/1024.0);
	else if (dcon->fi->size < 1073741824)
		g_snprintf(l_size, sizeof(l_size), "%.1fMB", (float)dcon->fi->size/1048576.0);
	else
		g_snprintf(l_size, sizeof(l_size), "%.1fGB", (float)dcon->fi->size/1073741824.0);

	switch (dcon->state) {
	case GS_WAITINGCONNECT:
		strcpy(l_status, "Connecting...");
		break;
	case GS_WAITINGPUSH:
		strcpy(l_status, "Push sent");
		break;
	case GS_FAILED:
		strcpy(l_status, "Failed");
		break;
	default:
		break;
	}

	g_snprintf(l_speed, sizeof(l_speed), "%d", dcon->fi->speed);

	memcpy(ip, ip2str(dcon->fi->ip), sizeof(ip));
	g_snprintf(l_server, sizeof(l_server), "[%s]:%d", ip, dcon->fi->port);

	gtk_clist_set_text(GTK_CLIST(download_list), row, 0, dcon->fi->file_name);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 1, l_size);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 2, l_status);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 3, l_speed);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 4, l_server);

	gl_options->dcons++;

	/* go to downloads */
	gtk_notebook_set_page(GTK_NOTEBOOK(main_notebook), 1);
}

void gui_update_download(struct newtella_connection *dcon)
{
	gchar l_status[255], l_speed[255] = "0.0 k/s";
	gint row;

	row = gtk_clist_find_row_from_data(GTK_CLIST(download_list), (gpointer) dcon);

	switch (dcon->state) {
	case GS_WAITINGCONNECT:
		strcpy(l_status, "Connecting...");
		break;
	case GS_WAITINGPUSH:
		strcpy(l_status, "Push sent");
		break;
	case GS_FAILED:
		strcpy(l_status, "Failed");
		break;
	case GS_NOTFOUND:
		strcpy(l_status, "Not Found");
		break;
	case GS_BUSY:
		strcpy(l_status, "Busy");
		break;
	case GS_COMPLETE:
		strcpy(l_status, "Done!");
		break;
	case GS_STOPPED:
		strcpy(l_status, "Stopped");
		break;
	case GS_CONNECTED:
		g_snprintf(l_speed, sizeof(l_speed), "%.1f k/s",
			   (float) (dcon->total_handled/(float)(time((time_t *)NULL)-dcon->last_time)/1000.0));
		g_snprintf(l_status, sizeof(l_status), "%.1f %%",
		(float) (dcon->total_handled/(float)dcon->fi->size)*100.0);

		break;
	default:
		break;
	}

	gtk_clist_set_text(GTK_CLIST(download_list), row, 2, l_status);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 3, l_speed);
}

void gui_update_download_status(struct newtella_connection *dcon, const gchar *reason)
{
	gint row = gtk_clist_find_row_from_data(GTK_CLIST(download_list), (gpointer) dcon);
	gtk_clist_set_text(GTK_CLIST(download_list), row, 2, reason);
}

void gui_add_upload(struct newtella_connection *ucon, char *file_name)
{
	gchar *dummy[5] = { "", "", "", "", "" };
	gchar l_size[255], l_status[255], l_speed[255] = "0.0 k/s", l_server[255];
	gchar ip[INET6_ADDRSTRLEN] = "\0";

	gint row = gtk_clist_append(GTK_CLIST(upload_list), dummy);
	gtk_clist_set_row_data(GTK_CLIST(upload_list), row, (gpointer) ucon);

	if (ucon->u_file_size < 1024)
		g_snprintf(l_size, sizeof(l_size), "%u Bytes", ucon->u_file_size);
	else if (ucon->u_file_size < 1048576)
		g_snprintf(l_size, sizeof(l_size), "%.1fKB", (float)ucon->u_file_size/1024.0);
	else if (ucon->u_file_size < 1073741824)
		g_snprintf(l_size, sizeof(l_size), "%.1fMB", (float)ucon->u_file_size/1048576.0);
	else
		g_snprintf(l_size, sizeof(l_size), "%.1fGB", (float)ucon->u_file_size/1073741824.0);

	switch (ucon->state) {
	case GS_HANDSHAKE:
		strcpy(l_status, "Handshaking...");
		break;
	case GS_FAILED:
		strcpy(l_status, "Failed");
		break;
	default:
		break;
	}

	memcpy(ip, ip2str(ucon->ip), sizeof(ip));
	g_snprintf(l_server, sizeof(l_server), "[%s]:%d", ip, ucon->port);

	gtk_clist_set_text(GTK_CLIST(upload_list), row, 0, file_name);
	gtk_clist_set_text(GTK_CLIST(upload_list), row, 1, l_size);
	gtk_clist_set_text(GTK_CLIST(upload_list), row, 2, l_status);
	gtk_clist_set_text(GTK_CLIST(upload_list), row, 3, l_speed);
	gtk_clist_set_text(GTK_CLIST(upload_list), row, 4, l_server);

	gl_options->ucons++;

	/* go to uploads */
	gtk_notebook_set_page(GTK_NOTEBOOK(main_notebook), 2);
}

void gui_update_upload(struct newtella_connection *ucon)
{
	gchar l_status[255], l_speed[255] = "0.0 k/s";
	gint row;
	static guint32 last = 0;
	guint32 now = time((time_t)NULL);
	row = gtk_clist_find_row_from_data(GTK_CLIST(upload_list), (gpointer) ucon);

	if (!last)
		last = now;

	if ((now - last < 1) && ucon->state == GS_CONNECTED)
		return;
	else
		last = now;

	switch (ucon->state) {
	case GS_WAITINGCONNECT:
		strcpy(l_status, "Connecting...");
		break;
	case GS_FAILED:
		strcpy(l_status, "Failed");
		break;
	case GS_STOPPED:
		strcpy(l_status, "Stopped");
		break;
	case GS_HANDSHAKE:
		strcpy(l_status, "Handshaking...");
		break;
	case GS_CONNECTED:
		g_snprintf(l_status, sizeof(l_status), "%.1f %%",
			   (float) (ucon->total_sent/(float)ucon->u_file_size)*100.0);
		g_snprintf(l_speed, sizeof(l_speed), "%.1f k/s",
			   (float) (ucon->total_sent/(float)(time((time_t *)NULL)-ucon->last_time)/1000.0));
		break;
	case GS_COMPLETE:
		strcpy(l_status, "Done!");
		break;
	default:
		break;
	}

	gtk_clist_set_text(GTK_CLIST(upload_list), row, 2, l_status);
	gtk_clist_set_text(GTK_CLIST(upload_list), row, 3, l_speed);

}

void gui_remove_con_from_list(struct newtella_connection *con)
{
	gint row;
	row = gtk_clist_find_row_from_data(GTK_CLIST(con_list), (gpointer) con);

	gl_options->cons--;

	gtk_clist_freeze(GTK_CLIST(con_list));
       	gtk_clist_remove(GTK_CLIST(con_list), row);
	gtk_clist_thaw(GTK_CLIST(con_list));
}

void gui_remove_download(struct newtella_connection *dcon)
{
	gint row = gtk_clist_find_row_from_data(GTK_CLIST(download_list), (gpointer) dcon);

	gl_options->dcons--;

	gtk_clist_remove(GTK_CLIST(download_list), row);
}

void gui_remove_upload(struct newtella_connection *ucon)
{
	gint row = gtk_clist_find_row_from_data(GTK_CLIST(upload_list), (gpointer) ucon);

	gl_options->ucons--;

	gtk_clist_remove(GTK_CLIST(upload_list), row);
}

void gui_reset_cons(void)
{
	GList *iter;
	struct newtella_connection *con;
	int i=0;

	iter = g_list_first(gl_con);
	while (iter) {
		i++;
		con = iter->data;
		//
		if (con->read_tag)
			gdk_input_remove(con->read_tag);
		if (con->write_tag)
			gdk_input_remove(con->write_tag);
		//

		close(con->s);
		newtella_free(con);

		iter = g_list_next(iter);
	}
	g_list_free(gl_con);
	gtk_clist_clear(GTK_CLIST(con_list));

	gl_con                = NULL;
	gl_options->cons      = 0;
	gl_options->connected = 0;
}

int gui_reset_host_cache(void)
{
	GList *iter;
	char buf[5];

	iter = g_list_first(gl_hosts_in_cache);
	while (iter) {
		newtella_free(iter->data);

		iter = g_list_next(iter);
	}

	g_list_free(gl_hosts_in_cache);
	gl_options->hosts_in_cache = 0;
	gl_hosts_in_cache = NULL;

        /* 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;
}

void gui_max_con_changed(void)
{
	gl_options->max_con =
		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(max_con));

	/* sanity check */
	if (gl_options->max_con < gl_options->min_con) {
		gl_options->max_con = gl_options->min_con;
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_con), gl_options->max_con);
	}

}

void gui_min_con_changed(void)
{
	gl_options->min_con =
		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(min_con));

        /* sanity check */
	if (gl_options->max_con < gl_options->min_con) {
		gl_options->min_con = gl_options->max_con;
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(min_con), gl_options->min_con);
	}

}

void gui_toggle_auto_connect(GtkToggleButton *toggle, gpointer data)
{
	gl_options->auto_connect = gtk_toggle_button_get_active(toggle);
}

void gui_toggle_accept_in_con(GtkToggleButton *toggle, gpointer data)
{
	gl_options->accept_in_con = gtk_toggle_button_get_active(toggle);

	if (!gl_options->accept_in_con)
		newtella_kill_server();
	else {
		if (!newtella_init_server(gl_options->newtella_port)) {
			gtk_toggle_button_set_active(toggle, FALSE);
		}
	}
}

void gui_add_con_old(void)
{
	guint16 port;
	struct IP ip;
	char *t, *l, *s = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(host_combo_box)->entry)));
	struct hostent *host;
	GList *temp_list;
	GtkWidget *new_list_item;
	//int errnum;

 	temp_list = GTK_LIST(GTK_COMBO(host_combo_box)->list)->children;

	/* Search the list for the host just added */
	while (temp_list && temp_list->data) {
		/* Get the string from the label */
		gtk_label_get(GTK_LABEL(GTK_BIN(temp_list->data)->child), &l);
		if (!l)
        		continue;
     		if (!g_strcasecmp(l, s))
			break;

		temp_list = temp_list->next;
	}

	if (temp_list == NULL)
	{
		/* The string was not found.
		   Therefore add it to the list
		*/
		new_list_item = gtk_list_item_new_with_label(s);
		gtk_widget_show(new_list_item);
		gtk_container_add(GTK_CONTAINER(GTK_COMBO(host_combo_box)->list), new_list_item);

	}

	if (strchr(s, '[')) {
	   t = memchr(s, ']', strlen(s));
	   *t++ = 0;
	   *t++ = 0;

	   port = atol(t);
	   host = gethostbyname2(s + 1, AF_INET6);

		if (host != NULL) {
			memcpy(ip.uints, host->h_addr, 16);
			con_add(ip.uints, port);

		} else
			perror("gethostbyname2");

	}

	else if (strchr(s, ':')) {

		t = memchr(s, ':', strlen(s));
		*t++ = 0;

		port = atol(t);
		host = gethostbyname2(s, AF_INET6);

		if (host != NULL) {
			memcpy(ip.uints, host->h_addr, 16);
			con_add(ip.uints, port);

		} else
			perror("gethostbyname2");

	}

	newtella_free(s);
}

void gui_add_con(void)
{
	guint16 port;
	struct IP ip;
	char *t, *l, *s = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(host_combo_box)->entry)));
	struct sockaddr_in6 *sin6;
	GList *temp_list;
	GtkWidget *new_list_item;
	struct addrinfo *res, *ressave, hints;
	int error;

 	temp_list = GTK_LIST(GTK_COMBO(host_combo_box)->list)->children;

	/* Search the list for the host just added */
	while (temp_list && temp_list->data) {
		/* Get the string from the label */
		gtk_label_get(GTK_LABEL(GTK_BIN(temp_list->data)->child), &l);
		if (!l)
        		continue;
     		if (!g_strcasecmp(l, s))
			break;

		temp_list = temp_list->next;
	}

	if (temp_list == NULL)
	{
		/* The string was not found.
		   Therefore add it to the list
		*/
		new_list_item = gtk_list_item_new_with_label(s);
		gtk_widget_show(new_list_item);
		gtk_container_add(GTK_CONTAINER(GTK_COMBO(host_combo_box)->list), new_list_item);

	}

	if (strchr(s, '[')) {
	   t = memchr(s, ']', strlen(s));
	   *t++ = 0;
	   *t++ = 0;

	   port = atol(t);

	   bzero(&hints, sizeof(hints));
	   hints.ai_family = AF_INET6;
	   hints.ai_socktype = SOCK_STREAM;

	   error = getaddrinfo(s + 1, t, &hints, &res);

		if (error == 0) {
			ressave = res;
			sin6 = (struct sockaddr_in6 *) res->ai_addr;
			while (host_is_private(&sin6->sin6_addr, 1) && res!= NULL){
				res = res->ai_next;
				sin6 = (struct sockaddr_in6 *) res->ai_addr;
			}
			bzero(ip.uints, sizeof(ip.uints));
			memcpy(ip.uints, &sin6->sin6_addr, sizeof(ip.uints)); // 16
			con_add(ip.uints, port);
			freeaddrinfo(ressave);
		} else
			perror("getaddrinfo");



	}

	else if (strchr(s, ':')) {

		t = memchr(s, ':', strlen(s));
		*t++ = 0;

		port = atol(t);

		bzero(&hints, sizeof(hints));
		hints.ai_family = AF_INET6;
	   	hints.ai_socktype = SOCK_STREAM;

	   	error = getaddrinfo(s, t, &hints, &res);

		if (error == 0) {
			ressave = res;
			sin6 = (struct sockaddr_in6 *) res->ai_addr;
			while (host_is_private(&sin6->sin6_addr, 1) && res!= NULL){
				res = res->ai_next;
				sin6 = (struct sockaddr_in6 *) res->ai_addr;
			}
			bzero(ip.uints, sizeof(ip.uints));
			memcpy(ip.uints, &sin6->sin6_addr, sizeof(ip.uints)); // 16
			con_add(ip.uints, port);
			freeaddrinfo(ressave);
		} else
			perror("getaddrinfo");

	}

	newtella_free(s);
}


void gui_launch_web_site(void)
{
	/* TODO Not really*/
}

void gui_about_gnewtellium(void)
{
	/* a little credit... */
	GtkWidget *about_window;
	GtkWidget *label;
	GtkWidget *button;
	GdkPixmap *pixmap;
	GtkWidget *pixmapwid;
	GdkBitmap *mask;
	GtkStyle  *style;
	gchar     *xpm_path;


	about_window = gtk_dialog_new();
	gtk_container_set_border_width(GTK_CONTAINER(about_window), 10);
        gtk_window_set_title(GTK_WINDOW(about_window), "About... "GNEWTELLIUM);


	xpm_path = strdup(PACKAGE_DATA_DIR"/pixmaps/gnewtellium.xpm");
	style = gtk_widget_get_style(window);

	pixmap = gdk_pixmap_create_from_xpm(window->window, &mask, &style->white, xpm_path);

	if (!pixmap)
		pixmap = gdk_pixmap_create_from_xpm_d(window->window, &mask,
						      &style->white,
						      gnewtellium_xpm);

	pixmapwid = gtk_pixmap_new(pixmap, mask);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about_window)->vbox), pixmapwid, FALSE, FALSE, 10);
	gtk_widget_show(pixmapwid);

	label = gtk_label_new("gnewtellium - Open Source Newtella for Unix\n"
			      "Version: "GNEWTELLIUM" "RELEASE_DATE" \n"
			      "Distributed under the GNU General Public License\n\n"
			      "IPv6-Modification (and some Fixes) by Frank Sowinski\n\n"
			      "Original developed by Elias Athanasopoulos\n"
                              "(elathan@users.sf.net)\n\n"
			      "Credits go to:\n"
			      "The Newtella folks for the financial,\n"
			      "psychological, technical, etc.-cal support\n"
			      "(http://rfc-gnutella.sourceforge.net)\n"
			      "Alex, the maintainer of the official web site\n"
			      "(avel@users.sf.net)\n"
			      "The Gnutella community...\n\n"
			      "News/Updates/Anything, please visit the official Web site\n"
			      GNEW_WEBSITE"\n\n"
			      "Share your love with us!...\n");

	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about_window)->vbox), label, FALSE, FALSE, 10);
	gtk_widget_show(label);

	button = gtk_button_new_with_label("Enough!");
	gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
				   GTK_SIGNAL_FUNC (gtk_widget_destroy),
				   GTK_OBJECT (about_window));


	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(about_window)->vbox), button, FALSE, FALSE, 10);
	gtk_widget_show(button);

	gtk_widget_show(about_window);
}

void gui_button_pressed(GtkWidget *widget, gpointer data)
{
	GList *iter;
	struct newtella_connection *dcon;
	struct newtella_connection *ucon;
	struct squery *new_query;
	time_t st;
	gchar buf[255], *time_str;
	gchar *query;

	/* main event handler for all buttons */
	switch ((int)data) {
	case BTN_ADV_CONFIG:
		config_draw();
		break;
	case BTN_STRT_SEARCH:
		/* add query to list */
		new_query = newtella_malloc(sizeof(struct squery));

		query = newtella_malloc(strlen(gtk_entry_get_text(GTK_ENTRY(search_edit_box)))+1);
		query = strcpy(query, gtk_entry_get_text(GTK_ENTRY(search_edit_box)));

		new_query->keyword = query;
		guidget(new_query->guid);

		gl_queries = g_slist_append(gl_queries, new_query);

		/* send broadcoast query */
		gnutella_send_query(new_query, NULL, 1);

		/* gui update */
		st = time((time_t *) NULL);
		time_str = ctime(&st); time_str[strlen(time_str)-1] = '\0';
		g_snprintf(buf, sizeof(buf), "Looking for: %s (%s)",
			   g_strdup(gtk_entry_get_text(GTK_ENTRY(search_edit_box))),
			   time_str);
		gtk_label_set_text(GTK_LABEL(status_label), buf);

		break;
	case BTN_SPRD_WORD:
		gui_launch_web_site();
		break;
	case BTN_ADD_CON:
		gui_add_con();
		break;
	case BTN_ABOUT:
		gui_about_gnewtellium();
		break;
	case BTN_CLR_SEARCH:
		gui_clean_found_results();
		break;
	case BTN_RESET_CON:
		gui_reset_cons();
		break;
	case BTN_CLR_HCACHE:
		gui_reset_host_cache();
		break;
	case BTN_EXIT: /* shutdown the application */

		/* close the server if it is alive */
		if (gl_options->accept_in_con)
			newtella_kill_server();

		/* shutdown gui */
		gtk_widget_destroy(window);

		/* save config/hosts */
		config_save_to_file();
		host_save_cache_to_file();

		/* bye... */
		gtk_exit(1);
		break;

        /* downloads */
	case BTN_DLD_START:
		iter = GTK_CLIST(download_list)->selection;
		if (iter) {
			dcon = (struct newtella_connection *)
				gtk_clist_get_row_data(GTK_CLIST(download_list),
						       (gint) iter->data);
			// Igor: Kein Resume bei Done
			if (dcon->state == GS_RESUME || dcon->state == GS_COMPLETE)
				break;

			if (dcon)
				download_resume(dcon);
		}
		break;
	case BTN_DLD_STOP:
		iter = GTK_CLIST(download_list)->selection;
		if (iter) {
			dcon = (struct newtella_connection *)
				gtk_clist_get_row_data(GTK_CLIST(download_list),
						       (gint) iter->data);
			// Igor: Kein Stop bei Done
			if (dcon && dcon->state != GS_COMPLETE)
				download_stop(dcon, "Stopped by user");

		}
		break;
	case BTN_DLD_KILL:
		iter = GTK_CLIST(download_list)->selection;
		if (iter) {
			dcon = (struct newtella_connection *)
				gtk_clist_get_row_data(GTK_CLIST(download_list),
						       (gint) iter->data);
			if (dcon)
				download_kill(dcon);
		}
		break;
	case BTN_DLD_CLEAR:
		iter = g_list_first(gl_down_con);
		while (iter) {
			dcon = iter->data;
			if (dcon->state == GS_FAILED || dcon->state == GS_COMPLETE) {
				download_kill(dcon);
				iter = g_list_first(gl_down_con);
			}else
				// Igor: Hier jetzt im else-Zweig, damit auch alle Einträge gelöscht werden
				iter = iter->next;
		}
		break;
	/* uploads */
	case BTN_ULD_STOP:
		iter = GTK_CLIST(upload_list)->selection;
		if (iter) {
			ucon = (struct newtella_connection *)
				gtk_clist_get_row_data(GTK_CLIST(upload_list),
						       (gint) iter->data);
			// Igor: Kein Stop bei Done
			if (ucon && ucon->state != GS_COMPLETE)
				upload_stop(ucon);
		}
		break;
	case BTN_ULD_KILL:
		iter = GTK_CLIST(upload_list)->selection;
		if (iter) {
			ucon = (struct newtella_connection *)
				gtk_clist_get_row_data(GTK_CLIST(upload_list),
						       (gint) iter->data);
			if (ucon)
				upload_kill(ucon);
		}
		break;
	case BTN_ULD_CLEAR:
		iter = g_list_first(gl_up_con);
		while (iter) {
			ucon = iter->data;

			if (ucon->state == GS_FAILED || ucon->state == GS_COMPLETE) {
				upload_kill(ucon);
				iter = g_list_first(gl_up_con);
			}else
				// Igor: Hier jetzt im else-Zweig, damit auch alle Einträge gelöscht werden
				iter = iter->next;
		}
		break;
	default:
		break;
	}
}

void gui_download_file(GtkWidget *gtkclist, gint row, gint col, GdkEventButton *event,
		       gpointer gdata)
{
	struct file_found *download_file;
	GList *iter;

        if (event->type != GDK_2BUTTON_PRESS)
		return;

	iter = g_list_nth(gl_results, row);
	download_file = iter->data;

	download_add(download_file);
}
