/***************************************************************************
                          toolbar.c  -  description
                             -------------------
    begin                : Sat Nov 23 2002
    copyright            : (C) 2002 by Tim-Philipp Müller
    email                : t.i.m@orange.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "colors.h"
#include "core-conn.h"
#include "disclosure-widget.h"
#include "dns_lookup.h"
#include "icons.h"
#include "http_get.h"
#include "linkhandler.h"
#include "mainwindow.h"
#include "misc.h"
#include "misc_gtk.h"
#include "misc_strings.h"
#include "notebook.h"
#include "options.h"
#include "search.h"

#include "servers.h"
#include "status_page.h"
#include "statusbar.h"
#include "toolbar.h"
#include "systray.h"

#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include <gtk/gtkeventbox.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkhandlebox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkstock.h>
#include <gtk/gtktooltips.h>
#include <gtk/gtkvbox.h>

#define TOOLBAR_MAX_SRV_NAME_LEN	30

/* local functions */

static void          onArrowToggled (GtkWidget *widget, gpointer data);
static GtkWidget	*toolbar_create_entry_field (void);
static GtkWidget	*toolbar_create_stats_box (void);
static void			 toolbar_go_button_onClicked (GtkWidget *widget, gpointer data);
static void			 toolbar_server_icon_onClicked (GtkWidget *widget, GdkEventButton *event, gpointer data);
static void			 toolbar_entry_clear (void);
static void			 toolbar_show_entry_help (void);
static void			 toolbar_do_website_search (const gchar *webengine, const gchar *websearch);
static gchar		*toolbar_sanitize_search_phrase (const gchar *search);

static void			 toolbar_onMenuShutdownCore (GtkWidget *widget, gpointer data);
/* static void			 toolbar_donkey_icon_popup_menu_kill_and_restart_core (GtkWidget *widget, gpointer pid); */
static void			 toolbar_donkey_icon_popup_menu_disconnect_core (GtkWidget *widget, gpointer data);
static void			 toolbar_donkey_icon_popup_menu_url (GtkWidget *widget, gpointer data);
static void			 toolbar_donkey_icon_onButtonPress (GtkWidget *widget, GdkEventButton *event, gpointer data);
static void			 toolbar_about_icon_onButtonPress (GtkWidget *widget, GdkEventButton *event, gpointer data);

static void      onCoreSpeedTotal (GuiCoreConn *conn, gfloat dlspeed, gfloat ulspeed, gpointer data);

static GtkWidget    *toolbar_create_about_menu (void);


/* local variables (these are here so we can set the style after window creation) */

static GSList        *toolbar_event_boxes;       /* NULL */ /* so we can set the style */
static GSList        *toolbar_list_entrywidgets; /* NULL */ /* need to be set to default style */
static GtkWidget     *toolbar_label_upspeed;     /* NULL */
static GtkWidget     *toolbar_label_downspeed;   /* NULL */
static GtkWidget     *toolbar_label_srvname;     /* NULL */
static GtkWidget     *toolbar_button_srvname;    /* NULL */
static GtkWidget     *toolbar_label_srvstats;    /* NULL */
static GtkWidget     *toolbar_label_cons;        /* NULL */

static GtkWidget     *overnetbox;            /* NULL */	/* event box that contains overnet logo */
static GtkWidget     *donkeybox;             /* NULL */ /* event box that contains edonkey logo */
static GtkWidget     *toolbar_handlebox;     /* NULL */
static GtkWidget     *toolbar_ew;            /* NULL */
static GtkWidget     *toolbar_hbox_stats;    /* NULL */
static GtkWidget     *toolbar_mainwindow;    /* NULL */

static gchar         *toolbar_core_version_string; /* NULL */



/******************************************************************************
 *
 *   toolbar_grab_focus
 *
 ***/

void
toolbar_grab_focus (void)
{
	gtk_widget_grab_focus (toolbar_ew);
}



/***************************************************************************
 *
 *   onCoreSpeedTotal
 *
 *   Signal handler for the "speed-total" signal emitted by the
 *    GuiCoreConn object after it has received a new upload/download
 *    status message pair from the core
 *
 ***************************************************************************/

static void
onCoreSpeedTotal (GuiCoreConn *conn, gfloat dlspeed, gfloat ulspeed, gpointer data)
{
	gchar buf[32];

	if (!toolbar_label_upspeed || !toolbar_label_downspeed)
		return;

	/* it's all ascii, no conversion to utf8 needed */
	g_snprintf (buf, sizeof(buf)/sizeof(gchar), "%3.1f  ", ulspeed);
	gtk_label_set_text(GTK_LABEL(toolbar_label_upspeed), buf);

	g_snprintf (buf, sizeof(buf)/sizeof(gchar), "%3.1f  ", dlspeed);
	gtk_label_set_text(GTK_LABEL(toolbar_label_downspeed), buf);
}


/***************************************************************************
 *
 *   onCoreOptions
 *
 ***************************************************************************/

static void
onCoreOptions (GuiCoreConn *conn, const CoreOptions *copts, gpointer data)
{
	gchar   cbdstr[128];      /* core build date string            */
	gchar  *cpidstr = NULL;   /* core pid string (if on localhost) */

	/* version string etc. doesn't change during a session */
	if (copts->num_gotten_opts > 0)
		return;

	g_snprintf (cbdstr, sizeof(cbdstr), " (build %02u%02u%04u)",
	                                     ((copts->builddate & 0xff    )      ),        /* day   */
	                                     ((copts->builddate & 0xff00  ) >>  8),        /* month */
	                                     ((copts->builddate & 0xff0000) >> 16)+2000);  /* year  */

	if (copts->pid > 0  &&  (guint)copts->pid != G_MAXUINT)
	{
		if (gui_core_conn_is_local (conn))
			cpidstr = g_strdup_printf (" (local pid=%u)", copts->pid);
		else
			cpidstr = g_strdup_printf (" (%spid=%u)", _("remote "), copts->pid);
	}
	else
	{
		const gchar *locstr = (gui_core_conn_is_local(conn)) ? _("local") : _("remote");
		cpidstr = g_strdup_printf (_(" (%s, pid not available)"), locstr);
	}

	G_FREE(toolbar_core_version_string);
	toolbar_core_version_string = g_strdup_printf ("%s: %u%s%s", _("Core version"), copts->version, cbdstr, cpidstr);

	linkhandler_check_for_pending_links();

	G_FREE(cpidstr);
}


/******************************************************************************
 *
 *   onCoreConnStatus
 *
 ******************************************************************************/

static void
onCoreConnStatus (GuiCoreConn *conn, guint status, gpointer data)
{
	if (status != CONN_STATUS_COMMUNICATING && status != CONN_STATUS_AUTHENTICATING)
	{
		gtk_label_set_text(GTK_LABEL(toolbar_label_upspeed),  " --- " );
		gtk_label_set_text(GTK_LABEL(toolbar_label_downspeed)," --- ");
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats), " ");
		gtk_label_set_text(GTK_LABEL(toolbar_label_cons),     " --- ");
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" not connected to a core yet ")));
		gtk_widget_queue_resize(toolbar_mainwindow);
	}
	else if (status == CONN_STATUS_AUTHENTICATING)
	{
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" [not connected] ")));
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats)," ");

		gtk_widget_show(donkeybox);
		gtk_widget_show(toolbar_button_srvname);
		gtk_widget_hide(overnetbox);
	}
}

/***************************************************************************
 *
 *   onClientStats
 *
 ***************************************************************************/

static void
onClientStats (GtkWidget *conslabel,
                       gfloat     temp,
                       gfloat     incoming,
                       gfloat     needed,
                       guint      clientid,
                       guint      cons,
                       guint      num_on_queue,
                       gpointer   data)
{
	static guint  max_core_connections_seen = 0;

	if (max_core_connections_seen == 0)
		max_core_connections_seen = opt_get_int(OPT_GUI_MAX_CONNECTIONS_SEEN);

	if (cons > 0)
	{
		max_core_connections_seen = MAX (max_core_connections_seen, cons);

		if (toolbar_label_cons != NULL)
			gtk_label_set_text(GTK_LABEL(conslabel), UTF8_SHORT_PRINTF(" %u :: %u ", cons, max_core_connections_seen));
	}

	opt_set_int (OPT_GUI_MAX_CONNECTIONS_SEEN, max_core_connections_seen);
}

/* toolbar_set_styles
 *
 *
 */

void
toolbar_set_styles (void)
{
	GtkStyle   *defstyle;
	GSList     *node;

	g_return_if_fail (toolbar_handlebox!=NULL);

	set_style_recursively (toolbar_handlebox, style_dark_green_background);

	for ( node = toolbar_event_boxes; node != NULL; node = node->next )
	{
		if (!node->data)
			continue;

		set_style_recursively (GTK_WIDGET(node->data), style_dark_green_background);
	}

	defstyle = gtk_widget_get_default_style();

	for ( node = toolbar_list_entrywidgets; node != NULL; node = node->next )
	{
		if (!node->data)
			continue;

		set_style_recursively (GTK_WIDGET(node->data), defstyle);
	}
}



/* toolbar_entry_clear
 *
 *
 */

static void
toolbar_entry_clear (void)
{
	g_return_if_fail (toolbar_ew != NULL);
	gtk_entry_set_text(GTK_ENTRY(toolbar_ew), "");
}


/* toolbar_sanitize_search_phrase
 *
 * Takes a search phrase (like 'many flying pigs')
 *  and makes sure that it does not contain bad characters
 *  and returns it in a form that can be used in URLs,
 *  e.g. 'many+flying+pigs'.
 *
 * search phrase should be in locale encoding, not utf8
 *
 * Returned string needs to be freed by caller!
 *
 */

static gchar *
toolbar_sanitize_search_phrase (const gchar *search)
{
	gchar	*s, *pos, **words, **word, *ret;
	GString	*final = NULL;

	g_return_val_if_fail (search!=NULL && *search!=0x00, NULL);

	s = g_ascii_strdown(search,-1);

	g_return_val_if_fail (s!=NULL, NULL);

	pos = s;

	while (*pos)
	{
		if ((g_ascii_iscntrl(*pos)) || (g_ascii_ispunct(*pos)))
		{
			*pos = ' ';
		}
		pos++;
	}
	

	words = g_strsplit (s, " ", 0);
	g_free(s);
	s = NULL;
	pos = NULL;
	g_return_val_if_fail (words!=NULL, NULL);

	word = words;
	while (*word)
	{
		if ((**word) && **word!=' ')
		{
			if (!final)
			{
				final = g_string_new(*word);
			} else final = g_string_append (final, *word);
			final = g_string_append_c (final, '+');
		}
		word++;
	}

	if (final)
	{
		/* cut of last '+' */
		final = g_string_truncate (final, final->len-1);
		ret = final->str;
		g_string_free (final, FALSE);
		final = NULL;
	} else ret = g_strdup("");

	g_strfreev(words);
	return ret;
}




/* toolbar_do_website_search
 *
 *
 */

static void
toolbar_do_website_search (const gchar *webengine, const gchar *websearch)
{
	gchar *url_template = NULL;

	g_return_if_fail (webengine!=NULL && *webengine!=0x00);
	g_return_if_fail (websearch!=NULL && *websearch!=0x00);

	/* jigle? */
	if (   g_ascii_strcasecmp(webengine,"jigle")  == 0
		|| g_ascii_strcasecmp(webengine,"jigl") == 0
		|| g_ascii_strcasecmp(webengine,"jig")  == 0
		|| g_ascii_strcasecmp(webengine,"ji")   == 0
		|| g_ascii_strcasecmp(webengine,"jg")   == 0
		|| g_ascii_strcasecmp(webengine,"j")    == 0)
	{
		url_template = "http://jigle.com/search?p=%s&ma=1&d=1&a=0&l=10&t=0&x=&sl=1&su=&v=0";
	}

	/* jigle audio? */
	else if ( g_ascii_strcasecmp(webengine,"ja")==0
		|| g_ascii_strcasecmp(webengine,"jaudio")==0
		|| g_ascii_strcasecmp(webengine,"jau")==0
		|| g_ascii_strcasecmp(webengine,"jmusic")==0
		|| g_ascii_strcasecmp(webengine,"jmus")==0)
	{
		url_template = "http://jigle.com/search?p=%s&ma=1&d=1&a=0&l=10&t=1&x=&sl=1&su=&v=0";
	}

	/* jigle video? */
	else if ( g_ascii_strcasecmp(webengine,"jv")==0
		|| g_ascii_strcasecmp(webengine,"jvideo")==0
		|| g_ascii_strcasecmp(webengine,"jvid")==0
		|| g_ascii_strcasecmp(webengine,"jmovie")==0
		|| g_ascii_strcasecmp(webengine,"jmov")==0)
	{
		url_template = "http://jigle.com/search?p=%s&ma=1&d=1&a=0&l=10&t=2&x=&sl=1&su=&v=0";
	}

	/* jigle program? */
	else if ( g_ascii_strcasecmp(webengine,"jp")==0
		|| g_ascii_strcasecmp(webengine,"jprogram")==0
		|| g_ascii_strcasecmp(webengine,"jprog")==0
		|| g_ascii_strcasecmp(webengine,"jpro")==0)
	{
		url_template = "http://jigle.com/search?p=%s&ma=1&d=1&a=0&l=10&t=4&x=&sl=1&su=&v=0";
	}

	/* imdb (general)? */
	else if (g_ascii_strcasecmp(webengine,"imdb")==0)
	{
		url_template = "http://us.imdb.com/Find?%s";
	}

	/* imdb (name/person)? */
	else if (g_ascii_strcasecmp(webengine,"name")==0
		|| g_ascii_strcasecmp(webengine,"person")==0
		|| g_ascii_strcasecmp(webengine,"name")==0
		|| g_ascii_strcasecmp(webengine,_("person"))==0)
	{
		url_template = "http://us.imdb.com/Nsearch?name=%s";
	}

	/* imdb (title)? */
	else if (g_ascii_strcasecmp(webengine,"title")==0
		|| g_ascii_strcasecmp(webengine,_("title"))==0)
	{
		url_template = "http://us.imdb.com/Tsearch?title=%s";
	}

	/* ShareReactor? */
	else if (g_ascii_strcasecmp(webengine,"sr")==0
		|| g_ascii_strcasecmp(webengine,"sharereactor")==0)
	{
		url_template = "http://www.sharereactor.com/search.php?search=%s&category=0&submit=Search";
	}

	/* FileNexus? */
	else if (g_ascii_strcasecmp(webengine,"fn")==0
		|| g_ascii_strcasecmp(webengine,"filenexus")==0)
	{
		statusbar_msg ("TODO: check whether fileNexus supports searching with http GET method.");
		return;
	}

	/* load serverlist? */
	else if (g_ascii_strcasecmp(webengine,"sl")==0
		|| g_ascii_strcasecmp(webengine,"met")==0)
	{
		if (!gui_core_conn_is_overnet(core) || gui_core_conn_is_hybrid(core))
		{
			if (websearch)
			{
				http_get_retrieve_serverlist (websearch,0);
			}
			else http_get_retrieve_serverlist (opt_get_str(OPT_GUI_SERVERLIST_URL_1),0);
		}
		else statusbar_msg (_("In overnet, you don't need to add servers."));

		return;
	}

	/* google? */
	else if (g_ascii_strcasecmp(webengine,"gg")==0
		|| g_ascii_strcasecmp(webengine,"google")==0)
	{
		url_template = "http://www.google.com/search?q=%s";
	}

	/* open browser? */
	else if (g_ascii_strcasecmp(webengine,"url")==0
		|| g_ascii_strcasecmp(webengine,"http")==0
		|| g_ascii_strcasecmp(webengine,"ftp")==0)
	{
		if (g_ascii_strcasecmp(webengine,"url")!=0)
		{
			gchar *url = g_strdup_printf("%s:%s", webengine, websearch);
			invoke_browser_with_url (url);
			g_free(url);
		} else invoke_browser_with_url (websearch);
		return;
	}

	if (url_template)
	{
		gchar *sane_search_phrase = toolbar_sanitize_search_phrase (websearch);
		gchar *url;

		g_return_if_fail (sane_search_phrase!=NULL && *sane_search_phrase!=0x00);

		/* TODO: should we sanity-check the template? (it must contain exactly one '%s') */

		url = g_strdup_printf (url_template, sane_search_phrase);
		g_return_if_fail (url!=NULL);
		g_free(sane_search_phrase);
		sane_search_phrase = NULL;
		
		/* fire up the browser! */
		invoke_browser_with_url (url);

		g_free(url);
		return;
	}

	misc_gtk_ok_dialog (GTK_MESSAGE_INFO, 
		_("\n"
		  " You typed something into the toolbar that \n"
		  " I could not interpret. Type 'help' to get \n"
		  " an overview of how you can use the toolbar. \n"));
}



/* toolbar_show_entry_help
 *
 *
 */

static void
toolbar_show_entry_help (void)
{
	GtkWidget	*dialog;
	GtkWidget	*text;
	GtkWidget	*frame, *framelabel;
	gchar           *help_utf8;

	const gchar *help = N_("<span size='medium'>"
				"<span color='blue'><b>\n"
				"  Normal search</b>:</span> just type one or more words. You need to be connected to a server.  \n"
				"<span color='blue'><b>\n"
				"  Jigle search"
				"</b></span>\n"
				"  <b>jg:</b><i>words</i> - searches jigle\n"
				"  <b>ja:</b><i>words</i> - searches jigle for audio files\n"
				"  <b>jv:</b><i>words</i> - searches jigle for video files\n"
				"  <b>jp:</b><i>words</i> - searches jigle for program files\n"
				"<span color='blue'><b>\n"
				"  ShareReactor search"
				"</b></span>\n"
				"  <b>sr:</b><i>words</i> - searches ShareReactor for files\n"
				"<span color='blue'><b>\n"
				"  Search Internet Movie Database"
				"</b></span> - external database, opens browser\n"
				"  <b>imdb:</b><i>words</i>  - searches the internet movies database (imdb.com)\n"
				"  <b>name:</b><i>words</i>  - searches the internet movies database for persons\n"
				"  <b>title:</b><i>words</i> - searches the internet movies database for film titles\n"
				"<span color='blue'><b>\n"
				"  Send advanced command to core/command line client"
				"</b></span>\n"
				"  <b>!</b><i>command</i>   - sends an advanced command to the core\n"
				"<span color='blue'><b>\n"
				"  Add server"
				"</b></span>\n"
				"  IP[:port]  - adds a server to the server list\n"
				"<span color='blue'><b>\n"
				"  Load serverlist via http"
				"</b></span>\n"
				"  <b>sl:</b><i>url</i> or <b>met:</b><i>url</i> - loads serverlist file from URL server.met or .html\n"
				"<span color='blue'><b>\n"
				"  Other stuff"
				"</b></span>\n"
				"  <b>gg:</b><i>words</i>     - search google\n"
				"  <b>url:</b><i>url</i>      - opens browser with given URL\n"
				"  <b>http://</b><i>bla</i> - opens browser with given URL\n"
				"  <b>cls</b>          - clears the status page window\n</span>");
				


	dialog = gtk_dialog_new_with_buttons(UTF8_SHORT_PRINTF("%s",_("how to use the ed2k-gtk-gui toolbar")),
	                                     GTK_WINDOW(toolbar_mainwindow), GTK_DIALOG_DESTROY_WITH_PARENT,
	                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);

	gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);

	gtk_container_set_border_width (GTK_CONTAINER(dialog), 15);


	text = gtk_label_new("");
	gtk_label_set_use_markup (GTK_LABEL(text), TRUE);
	help_utf8 = TO_UTF8(_(help)); /* get translation, then convert to UTF8 */
	gtk_label_set_markup (GTK_LABEL(text), help_utf8);
	gtk_widget_show (GTK_WIDGET(text));
	G_FREE(help_utf8);

	framelabel = gtk_label_new ("");
	gtk_label_set_use_markup (GTK_LABEL(framelabel), TRUE);
	gtk_label_set_markup (GTK_LABEL(framelabel), _("<span size='large' color='blue'><b>Toolbar Help</b></span>"));
	gtk_widget_show (framelabel);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_label_widget (GTK_FRAME(frame), framelabel);
	gtk_container_add (GTK_CONTAINER(frame), text);
	gtk_widget_show (frame);
	gtk_container_set_border_width (GTK_CONTAINER(frame), 10);

	gtk_container_add (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);

	gtk_widget_show(dialog);

	(void) gtk_dialog_run(GTK_DIALOG(dialog));

	gtk_widget_destroy(dialog);

}

/***************************************************************************
 *
 *   onStatusMessageFilteredOutput
 *
 ***************************************************************************/

static void
onStatusMessageFilteredOutput (GuiCoreConn *conn, const gchar *msg, GList **p_strlist)
{
	GList *node;

	g_assert(p_strlist != NULL);

	if (!msg)
		return;

	for (node = *p_strlist;  node != NULL;  node = node->next)
	{
		if (strcmp(msg, node->data) == 0)
		{
			g_free(node->data);
			*p_strlist = g_list_remove(*p_strlist, node->data);
			return;
		}
	}
}


/***************************************************************************
 *
 *   onStatusMessageUnfilteredOutput
 *
 ***************************************************************************/

static void
onStatusMessageUnfilteredOutput (GuiCoreConn *conn, const gchar *msg, GList **p_strlist)
{
	static gboolean   got_status_msg;   /* FALSE */

	g_assert(p_strlist != NULL);

	/* We might receive other non-status messages
	 *  until we get the output of the advanced
	 *  command back. A NULL msg argument means
	 *  that a non-status message has been received. */
	if (msg == NULL && got_status_msg == FALSE)
		return;

	/* We got all the output of the advanced
	 *  command. No need to get the status
	 *  messages unfiltered any longer. */
	if (msg == NULL && got_status_msg == TRUE)
	{
		GList *node;

		for (node = *p_strlist;  node != NULL;  node = node->next)
		{
			status_msg ("%s\n", (const gchar*)node->data);
			g_free(node->data);
		}

		g_list_free(*p_strlist);
		*p_strlist = NULL;

		got_status_msg = FALSE;

		g_signal_handlers_disconnect_by_func(conn, &onStatusMessageUnfilteredOutput, p_strlist);
		g_signal_handlers_disconnect_by_func(conn, &onStatusMessageFilteredOutput, p_strlist);

		return;
	}

//	status_msg ("%s\n", msg);
	*p_strlist = g_list_append(*p_strlist, g_strdup(msg));

	got_status_msg = TRUE;
}


/***************************************************************************
 *
 *   onStatusMessageUnfiltered
 *
 ***************************************************************************/

static void
onStatusMessageUnfiltered (GuiCoreConn *conn, const gchar *msg, gpointer data)
{
	guint users, files;

	/* edonkey cores send a protocol message for this info */
	if (!msg || !gui_core_conn_is_overnet(conn))
		return;

	if (sscanf(msg, "Users: %u   Files: %u", &users, &files) != 2)
		return;

	gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), "");
	gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats), UTF8_SHORT_PRINTF("%u  ", users));
}

/***************************************************************************
 *
 *   onStatusMessage
 *
 ***************************************************************************/

static void
onStatusMessage (GuiCoreConn *conn, const gchar *msg, gpointer data)
{
	if (g_ascii_strncasecmp(msg,"Connecting to",12) == 0)
	{
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" [connecting] ")));
		gtk_widget_queue_resize(toolbar_mainwindow);
	}
	else if (g_ascii_strncasecmp(msg,"Placed on connection Queue",25) == 0)
	{
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" [on connection queue] ")));
		gtk_widget_queue_resize(toolbar_mainwindow);
	}
}


/***************************************************************************
 *
 *   toolbar_go_button_onClicked
 *
 ***************************************************************************/

static void
toolbar_go_button_onClicked (GtkWidget *widget, gpointer data)
{
	gchar	*entrytext, *phrase, *dcolon;
	guint	 n1,n2,n3,n4,port=4661;

	entrytext = (gchar*) gtk_editable_get_chars (GTK_EDITABLE(toolbar_ew), 0, -1);

	phrase = entrytext;
	g_return_if_fail (entrytext!=NULL);

	if (!*phrase)
	{
		g_free(entrytext);
		return;
	}

	/* initial '?' is redundant. We'll skip it in order to
	 * retain syntax compatibility with Axel's bong
	 */
	if (*phrase == '?')
		phrase++;

	/* advanced command? */
	if (*phrase == '!')
	{
		if (phrase[1])
		{
			static GList *strlist; /* NULL */
			gchar        *msg;

			msg = g_strdup_printf (_("GUI: sending advanced command... '%s'\n"), phrase+1);
			status_msg ("%s", msg);
			gui_core_conn_send_command(core, phrase+1);
			notebook_set_page(NOTEBOOK_PAGE_STATUS);
			g_signal_connect(core, "status-message-unfiltered", (GCallback) onStatusMessageUnfilteredOutput, &strlist);
			g_signal_connect(core, "status-message",            (GCallback) onStatusMessageFilteredOutput,   &strlist);
			g_free (msg);
		}

		toolbar_entry_clear();
		g_free(entrytext);
		return;
	}

	/* help? */
	if ( *phrase == 0x00	/* if this happens, text was '?' */
		|| g_ascii_strcasecmp(phrase,"help") == 0
		|| g_utf8_collate(phrase,UTF8_SHORT_PRINTF("%s",_("help"))) == 0
		|| g_ascii_strncasecmp(phrase,"??",2) == 0 )
	{
		toolbar_show_entry_help();
		toolbar_entry_clear();
		g_free(entrytext);
		return;
	}

	/* cls? */
	if ( g_ascii_strcasecmp(phrase,"cls") == 0 )
	{
		status_page_clear();
		toolbar_entry_clear();
		g_free(entrytext);
		return;
	}

	/* cmdstats? */
	if ( g_ascii_strcasecmp(phrase,"cmdstats") == 0 )
	{
		gui_core_conn_dump_message_stats();
		toolbar_entry_clear();
		g_free(entrytext);
		return;
	}


	/* add server? */
	if (sscanf(phrase, "%u.%u.%u.%u:%u", &n1,&n2,&n3,&n4,&port)>=4)
	{
		if (n1<256 && n2<256 && n3<256 && n4<256 && port<65536)
		{
			guint32 ip = GUINT32_TO_LE (n1 | (n2 << 8) | (n3 << 16) | (n4 << 24));

			if (!gui_core_conn_is_overnet(core) || gui_core_conn_is_hybrid(core))
			{
				gui_core_conn_send_add_server(core, ip,port);
				gui_core_conn_send_get_serverlist(core);
				statusbar_msg (_("Server added."));
			} else statusbar_msg (_("In overnet, you don't need to add servers."));
			toolbar_entry_clear();
		} else statusbar_msg (_("Server not added - invalid format (must be n1.n2.n3.n4[:port]) with n=0-255"));
		return;
	}

	/* ed2k-link? */
	if (g_ascii_strncasecmp(phrase,"ed2k:",5)==0)
	{
		gint     num = -1;
		gboolean option_save = opt_get_bool(OPT_GUI_DOWNLOAD_ED2K_LINK_IMMEDIATELY);

		opt_set_bool(OPT_GUI_DOWNLOAD_ED2K_LINK_IMMEDIATELY, TRUE);

		misc_strings_unescape_url (phrase);  /* XXX - this routine is only meant to work with ASCII strings! */
		num = extract_ed2k_links (phrase);     /* phrase is utf8 here */

		opt_set_bool(OPT_GUI_DOWNLOAD_ED2K_LINK_IMMEDIATELY, option_save);

		if (num<=0)
		{
			statusbar_msg (_(" Entry field does not contain any ed2k-links!?"));
		} else statusbar_msg (_(" Processed %d ed2k-links."), num);

		toolbar_entry_clear();

		return;
	}

	/* special web site search request? */
	dcolon = strchr(phrase, ':');
	if (dcolon)
	{
		gchar *webengine = phrase;
		gchar *websearch = dcolon+1;
		*dcolon = 0x00;
		if (!*websearch)
		{
			g_free(entrytext);
			return;
		}
		toolbar_do_website_search (webengine, websearch);
		toolbar_entry_clear();
		g_free(entrytext);
		return;
	}

	if (toolbar_label_srvname)
	{
		const gchar *sname;

		sname = gtk_label_get_text (GTK_LABEL(toolbar_label_srvname));

		if (sname)
		{
			if ( !strstr(sname,"[not connected]")  &&  strncmp(sname, "---", 3) != 0 )
			{
				notebook_set_page(NOTEBOOK_PAGE_SEARCH);
				search_from_toolbar (phrase);
				toolbar_entry_clear();
				return;
			}
		}
	}
	
	/* if hybrid, search even if we are not connected to a server */
	if (gui_core_conn_is_hybrid(core))
	{
		notebook_set_page(NOTEBOOK_PAGE_SEARCH);
		search_from_toolbar (phrase);
		toolbar_entry_clear();
		return;
	}
	
	statusbar_msg (_("You must be connected to a server before you can search the eDonkey2000 network."));

	g_free(entrytext);
}



/* toolbar_server_icon_onclicked
 *
 *
 */

static void
toolbar_server_icon_onClicked (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	if (!gui_core_conn_is_overnet(core) || gui_core_conn_is_hybrid(core))
	{
		servers_toolbar_icon_popup_menu (event->button, event->time);
	}
	else
	{
		statusbar_msg (_("In overnet mode this menu is disabled."));
	}
}


/* toolbar_about_homepage_url
 *
 *
 */

static void
toolbar_about_homepage_url (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	invoke_browser_with_url(GUI_URL);
}


/* toolbar_donkey_icon_popup_menu_about
 *
 *
 *
 */

static void
toolbar_about_menu_onAbout (GtkWidget *widget, gpointer data)
{
	GtkWidget   *vbox, *eventbox;
	GtkWidget   *icon;
	GtkWidget   *jed_label, *tim_label,  *con_label, *locale_label;
	GtkWidget   *ver_label, *hp_label, *dialog;
	const gchar *charset = NULL;

	dialog = gtk_dialog_new_with_buttons (_(" About GUI and core "), GTK_WINDOW(toolbar_mainwindow),
	                                      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
	                                      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);

	vbox = GTK_DIALOG(dialog)->vbox;
	gtk_box_set_spacing (GTK_BOX(vbox), 15);

	icon = gtk_image_new_from_pixbuf (get_icon (ICON_TOOLBAR_ED2K_LOGO));
	gtk_widget_show (icon);
	gtk_box_pack_start (GTK_BOX (vbox), icon, TRUE, FALSE, 0);


	ver_label = gtk_label_new ("");
	gtk_label_set_use_markup (GTK_LABEL(ver_label), TRUE);
	gtk_label_set_markup (GTK_LABEL(ver_label), UTF8_SHORT_PRINTF("<span size='x-large' color='blue'><b>ed2k-gtk-gui version %s</b></span>\n(build %s %s)", VERSION, __DATE__, __TIME__));
	gtk_widget_show (ver_label);
	gtk_label_set_justify (GTK_LABEL (ver_label), GTK_JUSTIFY_CENTER);
	gtk_box_pack_start (GTK_BOX (vbox), ver_label, TRUE, FALSE, 0);

	jed_label = gtk_label_new ("");
	gtk_widget_show (jed_label);
	gtk_label_set_use_markup (GTK_LABEL (jed_label), TRUE);
	gtk_label_set_markup (GTK_LABEL(jed_label), UTF8_SHORT_PRINTF("%s", _("<span color='blue'><b>eDonkey 2000</b></span> was programmed by <b>Jed McCaleb</b> (jed@edonkey2000.com)")));
	gtk_label_set_justify (GTK_LABEL(jed_label), GTK_JUSTIFY_CENTER);
	gtk_box_pack_start (GTK_BOX (vbox), jed_label, TRUE, FALSE, 0);

	tim_label = gtk_label_new ("");
	gtk_widget_show (tim_label);
	gtk_label_set_use_markup (GTK_LABEL (tim_label), TRUE);
	gtk_label_set_markup (GTK_LABEL (tim_label), UTF8_SHORT_PRINTF("%s", _("<span color='blue'><b>This GUI</b></span> was programmed by <b>Tim-Philipp Muller</b> (tim@edonkey2000.com)")));
	gtk_label_set_justify (GTK_LABEL(tim_label), GTK_JUSTIFY_CENTER);
	gtk_box_pack_start (GTK_BOX (vbox), tim_label, TRUE, FALSE, 0);

	con_label = gtk_label_new ("");
	gtk_widget_show (con_label);
	gtk_label_set_use_markup (GTK_LABEL (con_label), TRUE);
	gtk_label_set_markup (GTK_LABEL (con_label), UTF8_SHORT_PRINTF(_("<span size='large' color='blue'><b>Contributors:</b></span>\n<b>%s</b> \n... and others."), CONTRIBUTORS));
	gtk_label_set_justify (GTK_LABEL(con_label), GTK_JUSTIFY_CENTER);
	gtk_box_pack_start (GTK_BOX (vbox), con_label, TRUE, FALSE, 0);

	ver_label = gtk_label_new (UTF8_SHORT_PRINTF("%s",toolbar_core_version_string));
	gtk_widget_show (ver_label);
	gtk_box_pack_start (GTK_BOX (vbox), ver_label, TRUE, FALSE, 0);

	(void) g_get_charset(&charset);
	locale_label = gtk_label_new (UTF8_SHORT_PRINTF(_("Your character encoding locale is: %s"),charset));
	gtk_widget_show (locale_label);
	gtk_box_pack_start (GTK_BOX (vbox), locale_label, TRUE, FALSE, 0);

	eventbox = gtk_event_box_new();
	gtk_widget_show (eventbox);
	hp_label = gtk_label_new (UTF8_SHORT_PRINTF("http://ed2k-gtk-gui.sourceforge.net"));
	gtk_label_set_pattern (GTK_LABEL(hp_label), "___________________________________");
	gtk_widget_show(hp_label);
	gtk_container_add (GTK_CONTAINER(eventbox), hp_label);
	g_signal_connect ( G_OBJECT (eventbox),
	                     "button_press_event",
	                     G_CALLBACK(toolbar_about_homepage_url),
	                     NULL);
	set_style_recursively (hp_label, style_url_label);
	gtk_box_pack_start (GTK_BOX (vbox), eventbox, TRUE, FALSE, 0);

	(void) gtk_dialog_run (GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}



/******************************************************************************
 *
 *  toolbar_donkey_icon_popup_menu_say_thank_you
 *
 *  The 'say thank you' button has been clicked 
 *
 ******************************************************************************/

static void
toolbar_about_menu_onSayThankyou (GtkWidget *widget, gpointer data)
{
	const gchar *txt = UTF8_SHORT_PRINTF(_("How to say 'Thank You' for this GUI:\n\n"
			"Send me an e-mail. Positive feedback always makes me happy.\n\n"
			"If this GUI makes you extremely happy, have a look at my amazon wishlist\n\n"
			"which you can find via http://ed2k-gtk-gui.sourceforge.net/wishlist.html  :)\n\n"
			"If you have any other feedback or suggestions, please let me know as well.\n\n"
			"tim@edonkey2000.com"));
	
	misc_gtk_ok_dialog (GTK_MESSAGE_INFO, txt);
}


/******************************************************************************
 *
 *  toolbar_onMenuShutdownCoreDialogResponse
 *
 ******************************************************************************/

static void
toolbar_onMenuShutdownCoreDialogResponse (GtkDialog *dialog, gint response, gpointer baz)
{
//	gtk_grab_remove(GTK_WIDGET(dialog));
	gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
	gtk_window_set_transient_for(GTK_WINDOW(dialog), NULL);
	gtk_widget_hide (GTK_WIDGET(dialog));
	gtk_widget_destroy(GTK_WIDGET(dialog));

	if (response == GTK_RESPONSE_YES)
	{
		status_message_blue (_("GUI: telling core to stop and shutdown...\n"));

		if (!gui_core_conn_is_overnet(core))
			dns_lookup_remove_dns_servers();

		gui_core_conn_send_logout(core);
	}
	else
	{
		statusbar_msg(_("Not shutting down core.\n"));
	}
}


/******************************************************************************
 *
 *  toolbar_onMenuShutdownCore
 *
 *  The 'shutdown core' button has been clicked.
 *  Check if we really want to shutdown the core
 *   and do it if the user is sure.
 *
 ******************************************************************************/

static void
toolbar_onMenuShutdownCore (GtkWidget *widget, gpointer data)
{
	const gchar *utf8;
	GtkWidget   *dialog;

	utf8 = UTF8_SHORT_PRINTF(_("\nDo you REALLY want to shutdown the core?\n\nAll downloads will stop.\n"));

	dialog = gtk_message_dialog_new ( GTK_WINDOW(toolbar_mainwindow),
	                                  0,
	                                  GTK_MESSAGE_WARNING,
	                                  GTK_BUTTONS_YES_NO,
	                                  utf8 );

	g_signal_connect(dialog, "response", (GCallback) toolbar_onMenuShutdownCoreDialogResponse, NULL);

//	gtk_grab_add(dialog);
	gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(toolbar_mainwindow));
	gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
	gtk_widget_show(dialog);
}

#warning *** TODO: re-enable kill_and_restart_core function again
#if 0
/******************************************************************************
 *
 * toolbar_donkey_icon_popup_menu_kill_and_restart_core
 *
 * The 'kill and restart core' button has been clicked.
 * Make sure that the user really wants this.
 *
 ***/

static void
toolbar_donkey_icon_popup_menu_kill_and_restart_core (GtkWidget *widget, gpointer pid)
{
	GtkWidget *dialog;
	gint       ret;

	dialog = gtk_message_dialog_new ( GTK_WINDOW(toolbar_mainwindow),
	                                  GTK_DIALOG_DESTROY_WITH_PARENT,
	                                  GTK_MESSAGE_WARNING,
	                                  GTK_BUTTONS_YES_NO,
	                                  _("\nDo you REALLY want to kill and restart the core?\n") );

	ret = gtk_dialog_run (GTK_DIALOG(dialog));

	gtk_widget_destroy(dialog);

	if ( ret != GTK_RESPONSE_YES )
		return;

	/* dokill_flag = 1 => kill it as well */
	kill_and_restart_core (GPOINTER_TO_UINT(pid), TRUE);
}
#endif

/* toolbar_donkey_icon_popup_menu_disconnect_core
 *
 * The 'close GUI-core connection' button has been clicked
 */

static void
toolbar_donkey_icon_popup_menu_disconnect_core (GtkWidget *widget, gpointer data)
{
	status_message_blue (_("GUI: closing connection (socket) to core...\n"));
	gui_core_conn_disconnect(core);
}

/* toolbar_donkey_icon_popup_menu_url
 *
 * a button that is supposed to call a browser with an URL has been clicked
 * data is a (gchar*) to the URL string.
 */

static void
toolbar_donkey_icon_popup_menu_url (GtkWidget *widget, gpointer data)
{
	g_return_if_fail (data!=NULL);
	invoke_browser_with_url ((gchar*)data);
}

/******************************************************************************
 *
 *   onExit
 *
 *   called when the 'exit eDonkey' item has been
 *    selected from the overnet/ed2k icon pop-down menu
 *
 ******************************************************************************/

static void
onExit (GtkWidget *widget, gpointer data)
{
	if (mainwindow_okay_to_exit())
	{
		gtk_main_quit();
	}
}


/******************************************************************************
 *
 *   toolbar_donkey_icon_onButtonPress
 *
 ******************************************************************************/

static void
toolbar_donkey_icon_onButtonPress (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	const CoreOptions *copts;
	GtkWidget         *menu;

	copts = gui_core_conn_get_core_options(core);

	menu  = gtk_menu_new();

	misc_gtk_add_submenu ( menu, _(" About "), ICON_ABOUT, toolbar_create_about_menu(), TRUE);

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" Disconnect from core "), toolbar_donkey_icon_popup_menu_disconnect_core, NULL, ICON_MENU_DISCONNECT, TRUE );

	misc_gtk_add_menu_item ( menu, _(" Exit eDonkey "), onExit, NULL, ICON_MENU_QUIT, TRUE );

	misc_gtk_add_menu_item ( menu, _(" Shutdown core "), toolbar_onMenuShutdownCore, NULL, ICON_SHUTDOWN, TRUE );

#if 0
	misc_gtk_add_menu_item ( menu, _(" Kill + restart core "), toolbar_donkey_icon_popup_menu_kill_and_restart_core,
	                         GUINT_TO_POINTER(copts->pid), ICON_MENU_REFRESH,
	                         (gui_core_conn_is_alive(core) && gui_core_conn_is_local(core) && copts->pid > 0
	                            &&  (guint)copts->pid != G_MAXUINT /* && first_time_we_get_options==0 */) );
#endif

	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
}


/******************************************************************************
 *
 *   toolbar_create_about_menu
 *
 *   returns the 'about' menu (we use it in 'about' button and 'core functions' popup)
 *
 ******************************************************************************/

static GtkWidget *
toolbar_create_about_menu (void)
{
	GtkWidget *menu;

	menu  = gtk_menu_new();

	misc_gtk_add_menu_item ( menu, _(" About GUI and core "), toolbar_about_menu_onAbout, NULL, ICON_ABOUT, TRUE);

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" Say \'thank you\' "), toolbar_about_menu_onSayThankyou, NULL, ICON_MENU_THANKYOU, TRUE);

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" ed2k-gtk-gui homepage "), toolbar_donkey_icon_popup_menu_url, GUI_URL, ICON_SYS_LINUX, TRUE);
	misc_gtk_add_menu_item ( menu, _(" ed2k-gtk-gui documentation "), toolbar_donkey_icon_popup_menu_url, DOCS_URL, ICON_FILETYPE_DOCUMENT, TRUE);

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" edonkey2000 homepage "), toolbar_donkey_icon_popup_menu_url, ED2K_URL, ICON_MENU_HOMEPAGE, TRUE);
	misc_gtk_add_menu_item ( menu, _(" overnet homepage "), toolbar_donkey_icon_popup_menu_url, OVERNET_URL, ICON_MENU_HOMEPAGE, TRUE);

	return menu;
}



/******************************************************************************
 *
 *   toolbar_about_icon_onButtonPress
 *
 ***/

static void
toolbar_about_icon_onButtonPress (GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	GtkWidget *menu;

	menu = toolbar_create_about_menu();

	gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
}



/******************************************************************************
 *
 *   onArrowToggled
 *
 ***/

static void
onArrowToggled (GtkWidget *widget, gpointer data)
{
	search_onShowSearchOptionsToggled(widget, data);
}


/******************************************************************************
 *
 *   toolbar_create_entry_field
 *
 ***/

static GtkWidget *
toolbar_create_entry_field (void)
{
	GtkWidget	*hbox;
	GtkTooltips *tooltips;
	gchar       *tiptxt_utf8;

	tooltips = gtk_tooltips_new();

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);

	/* disclosure widget (little arrow that shows/hides search options) */
	if (1)
	{
		GtkWidget   *arrow, *label;

		arrow = cddb_disclosure_new ("<span size=\"x-small\">options</span>", "<span size=\"x-small\">options</span>");

		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(arrow),
		                              opt_get_bool(OPT_GUI_TOOLBAR_SHOW_SEARCH_OPTIONS));

		label = gtk_bin_get_child(GTK_BIN(arrow));

		if ((label) && GTK_IS_LABEL(label))
			gtk_label_set_use_markup (GTK_LABEL(label),TRUE);

		g_signal_connect (arrow, "toggled", G_CALLBACK(onArrowToggled), NULL);
		gtk_widget_show(arrow);
		gtk_box_pack_start (GTK_BOX(hbox), arrow, FALSE, FALSE, 10);
		
		/* hide will options functionality isn't available */
		gtk_widget_hide (arrow);
	}



	toolbar_ew = gtk_entry_new();
	gtk_widget_show(toolbar_ew);
	toolbar_list_entrywidgets = g_slist_append (toolbar_list_entrywidgets, toolbar_ew);

	/* enter key = 'Go!' button pressed */
	g_signal_connect ( G_OBJECT(toolbar_ew), "activate",
	                     G_CALLBACK(toolbar_go_button_onClicked),
	                     toolbar_ew);

	g_signal_connect ( G_OBJECT(toolbar_ew), "changed",
	                   G_CALLBACK (search_onEntryWidgetChanged), NULL);


	tiptxt_utf8 = TO_UTF8(_("You can enter search phrases, ed2k-links, advanced commands, servers, and server list URLs here.\n"
	                        "Type 'help' in here to get more information.\n"
	                        "You can paste stuff from the clipboard with Control-V or by positioning "
	                        "the mouse pointer over the entry field and clicking the middle mouse button"));

	gtk_tooltips_set_tip(tooltips, toolbar_ew, tiptxt_utf8, NULL);

	G_FREE(tiptxt_utf8);

	gtk_box_pack_start (GTK_BOX (hbox), toolbar_ew, TRUE, TRUE, 1);

	return hbox;
}



/***************************************************************************
 *
 *   toolbar_create_stats_box
 *
 ***************************************************************************/

static GtkWidget *
toolbar_create_stats_box (void)
{
	GtkWidget   *hbox, *imgdown, *imgup, *imgcons, *button, *imgsrvbox;
	GtkTooltips *tooltips;
	gchar       *tooltxt_utf8;

	tooltips = gtk_tooltips_new();

	hbox = gtk_hbox_new(FALSE, 0);
	toolbar_hbox_stats = hbox;
	gtk_widget_show(hbox);

	/* down speed icon */

	imgdown = gtk_image_new_from_pixbuf (get_icon (ICON_TOOLBAR_DOWN_SPEED));
	gtk_widget_show(imgdown);
	gtk_box_pack_start (GTK_BOX(hbox), imgdown, FALSE, FALSE,0);

	/* down speed label */

	button = misc_gtk_new_tooltip_label_in_flat_button_box (&toolbar_label_downspeed,
	            UTF8_SHORT_PRINTF("%s",_("download speed in kB/s")));
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)button);
	gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 0);

	/* up speed icon */

	imgup =  gtk_image_new_from_pixbuf (get_icon (ICON_TOOLBAR_UP_SPEED));
	gtk_widget_show(imgup);
	gtk_box_pack_start (GTK_BOX(hbox), imgup, FALSE, FALSE,0);

	/* up speed label */

	button = misc_gtk_new_tooltip_label_in_flat_button_box (&toolbar_label_upspeed,
	            UTF8_SHORT_PRINTF("%s",_("upload speed in kB/s")));
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)button);
	gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 0);

	/* server */

	new_highlight_button_pack_and_signal_connect (&imgsrvbox, ICON_TOOLBAR_SERVER,
							toolbar_server_icon_onClicked, NULL);
	gtk_box_pack_start (GTK_BOX(hbox), imgsrvbox, FALSE, FALSE,0);

	/* server name */

	button = misc_gtk_new_tooltip_label_in_flat_button_box (&toolbar_label_srvname,
	            UTF8_SHORT_PRINTF("%s",_("name or IP of the server you are currently connected to")));
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)button);
	gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 0);
	toolbar_button_srvname = button;

	/* server users */

	button = misc_gtk_new_tooltip_label_in_flat_button_box (&toolbar_label_srvstats,
	            UTF8_SHORT_PRINTF("%s",_("Number of users connected to this server."
	                       "Note: eDonkey will search ALL known servers for sources.")));
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)button);
	gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 0);


	/* connections used icon */
	imgcons = gtk_image_new_from_pixbuf (get_icon (ICON_TOOLBAR_NUM_CONNECTIONS));
	gtk_widget_show(imgcons);
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)imgcons);
	gtk_box_pack_start (GTK_BOX(hbox), imgcons, FALSE, FALSE,0);

	/* connections used label */

	tooltxt_utf8 = TO_UTF8(_("Number of connections currently used by the core (and max.number seen)."
	                         "This value is not utterly important, it is just there to monitor whether "
	                         "your 'max.connections' setting in options is realistic."));
	button = misc_gtk_new_tooltip_label_in_flat_button_box (&toolbar_label_cons,tooltxt_utf8);
	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)button);
	gtk_box_pack_start (GTK_BOX(hbox), button, FALSE, FALSE, 0);
	G_FREE(tooltxt_utf8);

	g_signal_connect_swapped(core, "client-stats", (GCallback) onClientStats, toolbar_label_cons);

  gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" not connected to a core yet ")));
	gtk_label_set_text(GTK_LABEL(toolbar_label_upspeed),  " --- " );
	gtk_label_set_text(GTK_LABEL(toolbar_label_downspeed)," --- ");
	gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats), " ");
	gtk_label_set_text(GTK_LABEL(toolbar_label_cons),     " --- ");

	return hbox;
}


/******************************************************************************
 *
 *   onOvernetStatus
 *
 ******************************************************************************/

static void
onOvernetStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	gtk_widget_show(overnetbox);
	gtk_widget_hide(donkeybox);
	gtk_widget_hide(toolbar_button_srvname);
}

/******************************************************************************
 *
 *   onHybridStatus
 *
 ******************************************************************************/

static void
onHybridStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	gtk_widget_show(overnetbox);
	gtk_widget_show(donkeybox);
	gtk_widget_show(toolbar_button_srvname);
}

/******************************************************************************
 *
 *   onServerStats
 *
 ******************************************************************************/

static void
onServerStats (GuiCoreConn *conn, guint files, guint users, gpointer data)
{
	if (toolbar_label_srvstats)
		gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats), UTF8_SHORT_PRINTF(":: %u ", users));

	gtk_widget_queue_resize(toolbar_mainwindow);
}

/******************************************************************************
 *
 *   onServerConnected
 *
 ******************************************************************************/

static void
onServerConnected (GuiCoreConn *conn, const gchar *name, gpointer data)
{
	gchar *cleanname;

	/* is it really a servername? (don't want to cleanse our own '[bla]' strings */
	cleanname = misc_remove_junk_from_servername(name);

	if ((cleanname) && strlen(cleanname) > TOOLBAR_MAX_SRV_NAME_LEN+1)
	{
		cleanname[TOOLBAR_MAX_SRV_NAME_LEN]='>';
		cleanname[TOOLBAR_MAX_SRV_NAME_LEN+1]=0x00;
	}

	gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", (cleanname!=NULL) ? cleanname : name));

	gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats)," ");

	gtk_widget_queue_resize(toolbar_mainwindow);

	G_FREE(cleanname);
}

/******************************************************************************
 *
 *   onServerDisconnected
 *
 ******************************************************************************/

static void
onServerDisconnected (GuiCoreConn *conn, gpointer data)
{
	gtk_label_set_text(GTK_LABEL(toolbar_label_srvname), UTF8_SHORT_PRINTF("%s", _(" [not connected] ")));
	gtk_label_set_text(GTK_LABEL(toolbar_label_srvstats)," ");

	gtk_widget_queue_resize(toolbar_mainwindow);
}

/******************************************************************************
 *
 *   toolbar_create
 *
 ******************************************************************************/

GtkWidget *
toolbar_create (GtkWidget *mwindow)
{
	GtkWidget    *hbox, *hbox2, *vbox, *go_event_box, *hbox_go_about;
	GtkWidget    *aboutbox, *hbox_logos;
	GtkTooltips  *tooltips;
	GtkSizeGroup *sizegroup_go_about, *sizegroup_logos;

	toolbar_mainwindow = mwindow;

	sizegroup_go_about = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
	sizegroup_logos    = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);

	tooltips = gtk_tooltips_new();

	/* a vbox containing two rows of hboxes:
	 *  the normal toolbar in the top row, and extra search options in the second row */
	vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (vbox);

	hbox = gtk_hbox_new (FALSE, 0);
	gtk_widget_show(hbox);
	gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

	/* hbox2 is the whole upper row */
	hbox2 = search_create_options_hbox(sizegroup_go_about, sizegroup_logos, &toolbar_list_entrywidgets, &toolbar_event_boxes);
	gtk_box_pack_start (GTK_BOX(vbox), hbox2, TRUE, TRUE, 0);

	/* handle box */
	toolbar_handlebox = gtk_handle_box_new();
	gtk_widget_show(toolbar_handlebox);
	gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(toolbar_handlebox), GTK_SHADOW_NONE);
	gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(toolbar_handlebox), GTK_POS_RIGHT);
	gtk_container_add (GTK_CONTAINER (toolbar_handlebox), vbox);

	/* logo donkey */

	new_highlight_button_pack_and_signal_connect (&donkeybox, ICON_TOOLBAR_ED2K_LOGO,
	                                              toolbar_donkey_icon_onButtonPress, NULL);

	/* logo overnet */

	new_highlight_button_pack_and_signal_connect (&overnetbox, ICON_TOOLBAR_OVERNET_LOGO,
	                                              toolbar_donkey_icon_onButtonPress, NULL);
	gtk_widget_hide(overnetbox);


	/* we pack logos in one hbox, so we can use it with a GtkSizeGroup */
	hbox_logos = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (hbox_logos);
	gtk_size_group_add_widget (sizegroup_logos, hbox_logos);
	gtk_box_pack_start (GTK_BOX (hbox), hbox_logos, FALSE, FALSE, 0);

	gtk_box_pack_start (GTK_BOX (hbox_logos), donkeybox, FALSE, FALSE, 2);
	gtk_box_pack_start (GTK_BOX (hbox_logos), overnetbox, FALSE, FALSE, 2);

	gtk_box_pack_start (GTK_BOX (hbox), toolbar_create_stats_box (), FALSE, FALSE, 2);
	gtk_box_pack_start (GTK_BOX (hbox), toolbar_create_entry_field(), TRUE, TRUE, 2);

	/* we pack Go! button and about button in a hbox so we can use it with a GtkSizeGroup */

	hbox_go_about = gtk_hbox_new (FALSE, 0);
	gtk_widget_show(hbox_go_about);

	gtk_size_group_add_widget (sizegroup_go_about, hbox_go_about);

	/* 'Go!' button */

	new_highlight_button_pack_and_signal_connect (&go_event_box, ICON_TOOLBAR_GO,
							toolbar_go_button_onClicked, toolbar_ew);

	toolbar_event_boxes = g_slist_prepend (toolbar_event_boxes, (gpointer)go_event_box);

	gtk_box_pack_start (GTK_BOX (hbox_go_about), go_event_box, FALSE, FALSE, 10);

	GTK_WIDGET_SET_FLAGS (go_event_box, GTK_CAN_DEFAULT);

	/* 'about' button */

	new_highlight_button_pack_and_signal_connect (&aboutbox, ICON_TOOLBAR_ABOUT,
	                                              toolbar_about_icon_onButtonPress, NULL);

	gtk_box_pack_end (GTK_BOX(hbox_go_about), aboutbox, FALSE, FALSE, 10);

	gtk_box_pack_end (GTK_BOX (hbox), hbox_go_about, FALSE, FALSE, 10);

	g_signal_connect(core, "core-conn-status",          (GCallback) onCoreConnStatus,          NULL);
	g_signal_connect(core, "core-options",              (GCallback) onCoreOptions,             NULL);
	g_signal_connect(core, "speed-total",               (GCallback) onCoreSpeedTotal,          NULL);
	g_signal_connect(core, "server-stats",              (GCallback) onServerStats,             NULL);
	g_signal_connect(core, "server-connected",          (GCallback) onServerConnected,         NULL);
	g_signal_connect(core, "server-disconnected",       (GCallback) onServerDisconnected,      NULL);
	g_signal_connect(core, "overnet-status",            (GCallback) onOvernetStatus,           NULL);
	g_signal_connect(core, "hybrid-status",            (GCallback) onHybridStatus,           NULL);
	g_signal_connect(core, "status-message",            (GCallback) onStatusMessage,           NULL);
	g_signal_connect(core, "status-message-unfiltered", (GCallback) onStatusMessageUnfiltered, NULL);

	return toolbar_handlebox;
}


