/***************************************************************************
                          search_popup.c  -  description
                             -------------------
    begin                : Sat Mar 1 2003
    copyright            : (C) 2003 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 <gdk/gdkkeysyms.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtklabel.h>
#include <gtk/gtknotebook.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkvbox.h>

#include "blacklist.h"
#include "core-conn.h"
#include "filter.h"
#include "options.h"
#include "mainwindow.h"
#include "misc.h"
#include "misc_gtk.h"
#include "misc_strings.h"
#include "icons.h"
#include "search.h"
#include "search_popup.h"

#include "status_page.h"
#include "statusbar.h"

#ifdef G_OS_UNIX
# include <limits.h>
# include <unistd.h>
#endif

#ifndef MAXPATHLEN
# define MAXPATHLEN 512
#endif

/* imports from search.c */

extern GtkWidget    *ew_addsearch;
extern GtkWidget    *s_notebook;
extern GList        *searches;   /* contains pointers to Search structures */

extern GtkWidget    *button_extend;
extern GtkWidget    *button_more;


/* functions */

static GSList       *search_get_all_selected_iters (Search *search);

static void          search_onSelectAll (GtkWidget *widget, Search *search);

static void          search_onUnselectAll (GtkWidget *widget, Search *search);

static void          search_get_all_selected_iters_helper (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);

static void          search_onDownloadSelected (GtkWidget *widget, Search *search);

static void          search_onCustomDownloadSelected (GtkWidget *widget, Search *search);

static void          search_onWriteLink (GtkWidget *widget, Search *search);

static void          search_onCheckLinkHistory (GtkWidget *widget, Search *search);

static void          search_onShowAlternativeNames (GtkWidget *widget, Search *search);

static void          search_onAddToBlacklist (GtkWidget *widget, Search *search);

static void          search_onShowActiveFilters (GtkWidget *widget, gpointer data);

static void          search_onToggleShowFilesIHave (GtkWidget *widget, Search *search);

static void          search_onToggleShowBlacklistItems (GtkWidget *widget, Search *search);

static void          search_onToggleBoldFilenames (GtkWidget *widget, Search *search);

static void          search_onRotateTabs (GtkWidget *widget, gpointer data);

static void          search_onForgetSearch (GtkWidget *widget, Search *search);



/******************************************************************************
 *
 *   search_get_all_selected_iters
 *
 *   returns a GSList * with COPIES of all selected iters.
 *
 *   Iters and list must be freed by caller when finished.
 *
 ***/

static void
search_get_all_selected_iters_helper (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
	GSList **list = (GSList**) data;

	g_return_if_fail ( list != NULL );

	*list = g_slist_append ( *list, gtk_tree_iter_copy(iter) );
}

static GSList *
search_get_all_selected_iters (Search *search)
{
	GSList            *newlist = NULL;
	GtkTreeSelection  *selection;

	g_return_val_if_fail ( search != NULL, NULL );

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(search->view));

	gtk_tree_selection_selected_foreach ( selection, search_get_all_selected_iters_helper, &newlist );

	return newlist;
}



/******************************************************************************
 *
 *   search_onSelectAll
 *
 ***/

static void
search_onSelectAll (GtkWidget *widget, Search *search)
{
	GtkTreeSelection *selection;

	g_return_if_fail ( search != NULL );

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(search->view));

	gtk_tree_selection_select_all(selection);
}


/******************************************************************************
 *
 *   search_onUnselectAll
 *
 ***/

static void
search_onUnselectAll (GtkWidget *widget, Search *search)
{
	GtkTreeSelection *selection;

	g_return_if_fail ( search != NULL );

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(search->view));

	gtk_tree_selection_unselect_all(selection);
}


/******************************************************************************
 *
 *   search_onDownloadSelected
 *
 ***/

static void
search_onDownloadSelected (GtkWidget *widget, Search *search)
{
	GSList *selected, *node;

	g_return_if_fail ( search != NULL );

	selected = search_get_all_selected_iters(search);

	g_return_if_fail ( selected != NULL );

	for ( node = selected; node != NULL; node = node->next )
	{
		gchar        *name_utf8, *name_locale;
		guint8       *hash;
		guint         size;

		gtk_tree_model_get ( GTK_TREE_MODEL(search->store), (GtkTreeIter*) node->data,
		                     SEARCH_HASH_COL, &hash,
		                     SEARCH_SIZE_COL, &size,
		                     SEARCH_NAME_COL, &name_utf8,
		                     -1 );

		g_return_if_fail ( hash      != NULL       );
		g_return_if_fail ( name_utf8 != NULL       );
		g_return_if_fail ( size      <= 0xffffffff );

		name_locale = misc_strings_utf8_to_locale(name_utf8);

		g_return_if_fail ( name_locale != NULL );

		gui_core_conn_send_new_download(core, hash, (guint32) size, name_locale );

		g_free(name_utf8);
		g_free(name_locale);
		gtk_tree_iter_free((GtkTreeIter*) node->data);
	}

	g_slist_free(selected);
}


/******************************************************************************
 *
 *   search_onCustomDownloadSelected
 *
 ***/

static void
search_onCustomDownloadSelected (GtkWidget *widget, Search *search)
{
	GtkWidget  *dialog, *scrollwin, *vbox, **entry_fields;
	GSList     *selected, *node;
	gint        ret, num, i;

	g_return_if_fail ( search != NULL );

	selected = search_get_all_selected_iters(search);

	g_return_if_fail ( selected != NULL );

	dialog = gtk_dialog_new_with_buttons(UTF8_SHORT_PRINTF("%s",_("Download with custom filename")),
	                                     GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT,
	                                     GTK_STOCK_OK, GTK_RESPONSE_OK,
	                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);

	gtk_window_set_default_size (GTK_WINDOW(dialog), (gdk_screen_width()*4)/5, (gdk_screen_height()*3)/4);
	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);

	/* create a vbox to put all the entry fields in. vbox will go into the scrollwin */
	vbox = gtk_vbox_new (FALSE, 5);
	gtk_container_set_border_width (GTK_CONTAINER(vbox), 10);

	scrollwin = gtk_scrolled_window_new (NULL,NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrollwin), vbox);
	gtk_container_set_border_width (GTK_CONTAINER(scrollwin), 10);
	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 5);

	entry_fields = g_new0(GtkWidget*, g_slist_length(selected));

	num = 0;
	for ( node = selected; node != NULL; node = node->next )
	{
		GtkWidget    *label, *entry, *hbox, *dummylabel;
		gchar        *name_utf8, *label_txt; 
		guint8       *hash;
		guint         size;

		gtk_tree_model_get ( GTK_TREE_MODEL(search->store), (GtkTreeIter*) node->data,
		                     SEARCH_HASH_COL, &hash,
		                     SEARCH_SIZE_COL, &size,
		                     SEARCH_NAME_COL, &name_utf8,
		                     -1 );

		g_return_if_fail ( hash      != NULL       );
		g_return_if_fail ( name_utf8 != NULL       );
		g_return_if_fail ( size      <= 0xffffffff );

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

		gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 20);

		label = gtk_label_new(NULL);
		gtk_widget_show(label);

		label_txt = g_strconcat ( "<b><big>", name_utf8, "</big>  (", misc_get_human_size_utf8(NULL, 0, (guint)size), ")</b>", NULL );
		gtk_label_set_markup (GTK_LABEL(label), label_txt);
		gtk_label_set_justify (GTK_LABEL(label), GTK_JUSTIFY_LEFT);

		/* we need a hbox with a dummy label on the right so our
		 * real label justifies properly to the left */

		dummylabel = gtk_label_new(NULL);
		gtk_widget_show(dummylabel);

		gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
		gtk_box_pack_start (GTK_BOX(hbox), dummylabel, TRUE, TRUE, 0);

		entry = gtk_entry_new();
		gtk_widget_show(entry);
		gtk_entry_set_max_length(GTK_ENTRY(entry), MAXPATHLEN);

		entry_fields[num] = entry;
		g_object_set_data (G_OBJECT(entry), "filehash", hash);
		g_object_set_data (G_OBJECT(entry), "filesize", GUINT_TO_POINTER(size));

		gtk_box_pack_start (GTK_BOX(vbox), entry, TRUE, TRUE, 0);

		gtk_entry_set_text ( GTK_ENTRY(entry), name_utf8 );

		G_FREE(name_utf8);
		G_FREE(label_txt);

		gtk_tree_iter_free((GtkTreeIter*) node->data);

		num++;
	}

	gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);

	ret = gtk_dialog_run(GTK_DIALOG(dialog));

	if ( ret != GTK_RESPONSE_OK )
	{
		gtk_widget_destroy(dialog);
		g_slist_free(selected);
		return;
	}

	for ( i = 0; i < num; i++ )
	{
		GtkWidget     *one_entry;
		const guint8  *hash;
		gchar         *name_utf8, *name_locale;
		guint          size;

		g_return_if_fail ( entry_fields != NULL );

		one_entry = entry_fields[i];
		size = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(one_entry), "filesize"));
		hash = g_object_get_data(G_OBJECT(one_entry), "filehash");
		name_utf8 = gtk_editable_get_chars (GTK_EDITABLE(one_entry), 0, -1);

		g_return_if_fail ( size       > 0    );
		g_return_if_fail ( hash      != NULL );
		g_return_if_fail ( name_utf8 != NULL );

		name_locale = misc_strings_utf8_to_locale(name_utf8);

		if (!name_locale)
			name_locale = g_strdup(name_utf8);

		gui_core_conn_send_new_download(core, hash, (guint32) size, name_locale );

		G_FREE(name_locale);
		G_FREE(name_utf8);
	}

	gtk_widget_destroy(dialog);
	g_slist_free(selected);
}

/******************************************************************************
 *
 *   search_onCheckLinkHistory
 *
 ***/

static void
search_onCheckLinkHistory (GtkWidget *widget, Search *search)
{
	GSList *selected, *l;

	g_return_if_fail (search != NULL);

	selected = search_get_all_selected_iters (search);

	g_return_if_fail (selected != NULL);

	for (l = selected; l; l = l->next )
	{
		guint8  *hash;
		gchar   *url;
		
		gtk_tree_model_get (GTK_TREE_MODEL (search->store), (GtkTreeIter*) l->data,
		                     SEARCH_HASH_COL, &hash,
		                     -1 );

		g_return_if_fail (hash != NULL);

		url = g_strdup_printf ("http://stats.razorback2.com/ed2khistory?ed2k=%s", 
		                       hash_to_hash_str (hash));
		
		invoke_browser_with_url (url);

		gtk_tree_iter_free((GtkTreeIter*) l->data);
		g_free (url);
	}

	g_slist_free (selected);
}

/******************************************************************************
 *
 *   search_onWriteLink
 *
 ***/

static void
search_onWriteLink (GtkWidget *widget, Search *search)
{
	GSList *selected, *node;

	g_return_if_fail ( search != NULL );

	selected = search_get_all_selected_iters(search);

	g_return_if_fail ( selected != NULL );

	/* to make sure selection is only one link, for cut'n'paste to
	 * fake search engines this is easier (if only one file was selected in list, that is) */
	status_msg (" \n");

	for ( node = selected; node != NULL; node = node->next )
	{
		gchar        *name_utf8;
		guint8       *hash;
		guint         size;

		gtk_tree_model_get ( GTK_TREE_MODEL(search->store), (GtkTreeIter*) node->data,
		                     SEARCH_HASH_COL, &hash,
		                     SEARCH_SIZE_COL, &size,
		                     SEARCH_NAME_COL, &name_utf8,
		                     -1 );

		g_return_if_fail ( hash      != NULL       );
		g_return_if_fail ( name_utf8 != NULL       );
		g_return_if_fail ( size      <= 0xffffffff );

		status_msg_print_ed2klink (name_utf8, (guint32)size, hash);

		g_free(name_utf8);
		gtk_tree_iter_free((GtkTreeIter*) node->data);
	}

	g_slist_free(selected);
}


/******************************************************************************
 *
 *   search_onShowAlternativeNames
 *
 *   XXX - we should use a tree store instead of this alternative names stuff!
 *
 ***/

static void
search_onShowAlternativeNames (GtkWidget *widget, Search *search)
{
	GSList *selected, *node;

	g_return_if_fail ( search != NULL );

	selected = search_get_all_selected_iters(search);

	g_return_if_fail ( selected != NULL );

	for ( node = selected; node != NULL; node = node->next )
	{
		gchar        *name_utf8, *text;
		GSList       *alt_names, *alt_node;

		gtk_tree_model_get ( GTK_TREE_MODEL(search->store), (GtkTreeIter*) node->data,
		                     SEARCH_ALTNAMES_COL, &alt_names,
		                     SEARCH_NAME_COL, &name_utf8,
		                     -1 );

		g_return_if_fail ( name_utf8 != NULL );

		if ( !alt_names )
		{
			text = g_strconcat ( name_utf8, " \n\n",
			                     UTF8_SHORT_PRINTF("%s", _("I'm not aware of any alternative names for this file.\n") ),
			                     NULL );
		}
		else
		{
			text = g_strconcat ( name_utf8, "\n",
			                     UTF8_SHORT_PRINTF("%s", _("names file is known under on other servers")),
		                         ":\n\n", NULL );

			for ( alt_node = alt_names; alt_node != NULL; alt_node = alt_node->next )
			{
				gchar *text2 = g_strconcat ( text, (gchar*) alt_node->data, NULL );

				g_free(text);

				text = text2;
			}
		}

		misc_gtk_ok_dialog (GTK_MESSAGE_INFO, text);

		G_FREE(text);
		g_free(name_utf8);
		gtk_tree_iter_free((GtkTreeIter*) node->data);
	}

	g_slist_free(selected);
}



/******************************************************************************
 *
 *   search_onAddToBlacklist
 *
 ***/

static void
search_onAddToBlacklist (GtkWidget *widget, Search *search)
{
	GSList *selected, *node;

	g_return_if_fail ( search != NULL );

	selected = search_get_all_selected_iters(search);

	g_return_if_fail ( selected != NULL );

	/* to make sure selection is only one link, for cut'n'paste to
	 * fake search engines this is easier (if only one file was selected in list, that is) */
	status_msg (" \n");

	for ( node = selected; node != NULL; node = node->next )
	{
		gchar   *name_utf8;
		guint8  *hash;
		guint    flags;
		guint    size;

		gtk_tree_model_get ( GTK_TREE_MODEL(search->store), (GtkTreeIter*) node->data,
		                     SEARCH_HASH_COL, &hash,
		                     SEARCH_SIZE_COL, &size,
		                     SEARCH_NAME_COL, &name_utf8,
		                     SEARCH_FLAGS_COL, &flags,
		                     -1 );

		g_return_if_fail ( hash      != NULL       );
		g_return_if_fail ( name_utf8 != NULL       );
		g_return_if_fail ( size      <= 0xffffffff );

		add_to_blacklist (hash, (guint32)size, name_utf8);

		gtk_list_store_set ( search->store, (GtkTreeIter*) node->data,
		                     SEARCH_ICON_COL, get_icon (ICON_MENU_BLACKLIST),
		                     SEARCH_FLAGS_COL, (flags | SEARCH_FLAG_BLACKLISTED),
		                     -1 );

		g_free(name_utf8);
		gtk_tree_iter_free((GtkTreeIter*) node->data);
	}

	g_slist_free(selected);
}


/******************************************************************************
 *
 *   search_onMoreResults
 *
 ***/

void
search_onMoreResults (GtkWidget *widget, Search *search)
{
	statusbar_msg (_(" Okay, asked server for 200 more results."));

	gui_core_conn_send_more_search(core);
}


/******************************************************************************
 *
 *   search_onExtendSearch
 *
 ******************************************************************************/

void
search_onExtendSearch (GtkWidget *widget, Search *search)
{
	if (!search)
		search = search_get_current_search();

	g_return_if_fail (search != NULL);
	g_return_if_fail (search->isUserList == FALSE);

	gui_core_conn_send_extended_search(core);
	gui_core_conn_send_extended_search(core);
	gui_core_conn_send_extended_search(core);
	gui_core_conn_send_extended_search(core);
	gui_core_conn_send_extended_search(core);
}


/******************************************************************************
 *
 *   search_onShowActiveFilters
 *
 ***/

static void
search_onShowActiveFilters (GtkWidget *widget, gpointer data)
{
	GString  *str;
	GSList   *node;

	if (!filters)
	{
		statusbar_msg (_(" No filters?!"));
		return;
	}

	str = g_string_new(_("Active filters:\n\n"));

	g_return_if_fail (str!=NULL);

	for ( node = filters;  node != NULL;  node = node->next )
	{
		const gchar *filterword = (const gchar*)node->data;

		if (!filterword)
			continue;

		if ( *filterword == '*' )
		{
			str = g_string_append (str, filterword+1);
			str = g_string_append (str, _(" (whole word)\n"));
		}
		else
		{
			str = g_string_append (str, filterword);
			str = g_string_append (str, _(" (substring)\n"));
		}
	}

	misc_gtk_ok_dialog (GTK_MESSAGE_INFO, str->str);

	g_string_free (str,TRUE);
}


/******************************************************************************
 *
 *   search_onToggleShowFilesIHave
 *
 ***/

static void
search_onToggleShowFilesIHave (GtkWidget *widget, Search *search)
{
	opt_toggle_bool(OPT_GUI_SEARCH_SHOW_OWN_FILES);

	if ( !opt_get_bool(OPT_GUI_SEARCH_SHOW_OWN_FILES) )
		search_remove_all (search, SEARCH_FLAG_ALREADY_HAVE_THIS);
}


/******************************************************************************
 *
 *   search_onToggleShowBlacklistItems
 *
 ***/

static void
search_onToggleShowBlacklistItems (GtkWidget *widget, Search *search)
{
	opt_toggle_bool(OPT_GUI_SEARCH_SHOW_BLACKLISTED_ITEMS);

	if ( !opt_get_bool(OPT_GUI_SEARCH_SHOW_BLACKLISTED_ITEMS))
		search_remove_all (search, SEARCH_FLAG_BLACKLISTED);
}


/******************************************************************************
 *
 *   search_onToggleBoldFilenames
 *
 ***/

static void
search_onToggleBoldFilenames (GtkWidget *widget, Search *search)
{
	opt_toggle_bool(OPT_GUI_SEARCH_FILENAMES_BOLD);

	search_update_filename_weight_set();
}

/******************************************************************************
 *
 *   search_onToggleIcons
 *
 ***/

static void
search_onToggleIcons (GtkWidget *widget, Search *search)
{
	if (opt_get_bool(OPT_GUI_SHOW_ICONS_IN_SEARCH_LIST))
	{
		statusbar_msg (_("GUI: Search icons will be turned off in the future."));
	}
	else
	{
		statusbar_msg (_("GUI: Search icons will be turned on in the future."));
	}

	opt_toggle_bool(OPT_GUI_SHOW_ICONS_IN_SEARCH_LIST);
}

/******************************************************************************
 *
 *   search_onRotateTabs
 *
 ***/

static void
search_onRotateTabs (GtkWidget *widget, gpointer data)
{
	g_return_if_fail ( s_notebook != NULL );

	switch (opt_get_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS))
	{
		case GTK_POS_LEFT:    opt_set_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS, GTK_POS_TOP);
		break;
		case GTK_POS_RIGHT:   opt_set_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS, GTK_POS_BOTTOM);
		break;
		case GTK_POS_TOP:     opt_set_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS, GTK_POS_RIGHT);
		break;
		case GTK_POS_BOTTOM:  opt_set_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS, GTK_POS_LEFT);
		break;
	}

	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(s_notebook), (GtkPositionType)opt_get_int(OPT_GUI_SEARCH_NOTEBOOK_TAB_POS));
}


/******************************************************************************
 *
 *   search_onForgetSearch
 *
 ***/

static void
search_onForgetSearch (GtkWidget *widget, Search *search)
{
	g_return_if_fail ( search != NULL );

	search_delete (search);
}


/******************************************************************************
 *
 *   search_popup_menu
 *
 ***/

void
search_popup_menu (GtkWidget *widget, GdkEventButton *event, Search *search)
{
	GtkTreeSelection  *selection;
	GtkWidget         *menu, *omenu;
	guint              sel_count;
	gboolean           last_search = ( search == (Search*) g_list_last(searches));

	IconName           icon_yes = ICON_OPTION_TRUE;
	IconName           icon_no  = ICON_OPTION_FALSE;

	g_return_if_fail ( search != NULL );

	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(search->view));
	sel_count = misc_gtk_tree_selection_count_selected_rows (selection);

	/* search options sub-menu */

	omenu  = gtk_menu_new();

	misc_gtk_add_menu_item ( omenu, _(" show files I have among search results (in next search)"),
	                         search_onToggleShowFilesIHave, search,
	                         (opt_get_bool(OPT_GUI_SEARCH_SHOW_OWN_FILES)) ? icon_yes : icon_no, TRUE );

	misc_gtk_add_menu_item ( omenu, _(" show items on blacklist in grey (instead of hiding them)"),
	                         search_onToggleShowBlacklistItems, search,
	                         (opt_get_bool(OPT_GUI_SEARCH_SHOW_BLACKLISTED_ITEMS)) ? icon_yes : icon_no, TRUE );

	misc_gtk_add_menu_item ( omenu, _(" show filenames in bold print "),
	                         search_onToggleBoldFilenames, search,
	                         (opt_get_bool(OPT_GUI_SEARCH_FILENAMES_BOLD)) ? icon_yes : icon_no, TRUE );

	misc_gtk_add_menu_item ( omenu, _(" show icons "),
	                         search_onToggleIcons, search,
	                         (opt_get_bool(OPT_GUI_SHOW_ICONS_IN_SEARCH_LIST)) ? icon_yes : icon_no, TRUE );

	misc_gtk_add_menu_separator ( omenu );

	misc_gtk_add_menu_item ( omenu, _(" change the search notebook tabs' position (rotate clockwise)"),
	                         search_onRotateTabs, search, ICON_MENU_REFRESH, TRUE );


	/* main pop-up menu */

	menu  = gtk_menu_new();

  misc_gtk_add_menu_header(menu, _("Search results"), NULL);

	misc_gtk_add_menu_item ( menu, _(" select all"), search_onSelectAll, search,
	                         ICON_NONE, TRUE );

	misc_gtk_add_menu_item ( menu, _(" unselect all"), search_onUnselectAll, search,
	                         ICON_NONE, (sel_count>0) );

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" download selected items"),
	                         search_onDownloadSelected, search,
	                         ICON_MENU_DOWNLOAD, ( sel_count > 0 && !search->isUserList ) );

	misc_gtk_add_menu_item ( menu, _(" download selected items with custom filenames"),
	                         search_onCustomDownloadSelected, search,
	                         ICON_MENU_DOWNLOAD, ( sel_count > 0 && !search->isUserList ) );

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" write ed2k-link to log/clipboard "),
	                         search_onWriteLink, search,
	                         ICON_MENU_STATUS, ( sel_count > 0 && !search->isUserList ) );

	if (!gui_core_conn_is_overnet(core) || gui_core_conn_is_hybrid(core))
	{
		misc_gtk_add_menu_item ( menu, _(" show names file is known under on other servers "),
		                         search_onShowAlternativeNames, search,
		                         ICON_MENU_ABOUT, ( sel_count > 0 && !search->isUserList ) );
	}

	misc_gtk_add_menu_item (menu, _(" check razorback history for file "),
	                        search_onCheckLinkHistory, search,
	                        ICON_MENU_ABOUT, (sel_count > 0 && !search->isUserList));
	
	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_menu_item ( menu, _(" add item to blacklist (by hash+size) "),
	                         search_onAddToBlacklist, search,
	                         ICON_MENU_BLACKLIST, ( sel_count > 0 && !search->isUserList ) );

	misc_gtk_add_menu_separator ( menu );

	if (!gui_core_conn_is_overnet(core) || gui_core_conn_is_hybrid(core))
	{

		misc_gtk_add_menu_item ( menu, _(" get the next 200 search results "),
		                         search_onMoreResults, search,
		                         ICON_MENU_200, GTK_WIDGET_SENSITIVE(button_more) && last_search );

		misc_gtk_add_menu_item ( menu, _(" extend search to five other servers "),
		                         search_onExtendSearch, search,
		                         ICON_MENU_EXTEND, GTK_WIDGET_SENSITIVE(button_extend) && last_search );

		misc_gtk_add_menu_separator ( menu );
	}

	if (1)
	{
		static gboolean msg_shown = FALSE;
		if (!msg_shown)
			g_print ("IMPLEMENT: user stuff in search pop-up menu (current core doesn't support it though)\n");
		msg_shown = TRUE;
//		item1 =  add_menuitem (menu, " show this user's files", search_menuitem_showuserfiles, NULL, ICON_NONE);
//		item1b = add_menuitem (menu, " add user to friends list", search_menuitem_addtofriends, NULL, ICON_NONE);
//		gtk_widget_set_sensitive (item1b, (GTK_CLIST(clist_search)->selection != NULL) );
	}

	misc_gtk_add_menu_item ( menu, _(" show list of active filters (temporary) "),
	                         search_onShowActiveFilters, NULL, ICON_NONE, TRUE );

	misc_gtk_add_menu_separator ( menu );


	misc_gtk_add_menu_item ( menu, _(" forget this search "),
	                         search_onForgetSearch, search,
	                         ICON_MENU_CANCEL, TRUE);

	misc_gtk_add_menu_separator ( menu );

	misc_gtk_add_submenu ( menu, _(" search list options "), ICON_MENU_OPTIONS, omenu, TRUE );

	gtk_widget_show(menu);

	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, (event) ? event->button : 0, gdk_event_get_time((GdkEvent*)event));

}


/******************************************************************************
 *
 *   search_onKeyPress
 *
 ***/

gboolean
search_onKeyPress (GtkWidget *widget, GdkEventKey *event, Search *search)
{
	static guint  last_key = 0;
	gboolean      ret = TRUE;
	guint         key = gdk_keyval_to_lower(event->keyval);

	g_return_val_if_fail ( search != NULL, FALSE );

	if ( search->isUserList )
		g_return_val_if_reached (FALSE);

	switch (key)
	{
		case GDK_Return:
		{
			if ( last_key == GDK_Shift_L || last_key == GDK_Shift_R )
			{
				search_onCustomDownloadSelected (NULL, search);
			}
			else
			{
				search_onDownloadSelected (NULL, search);
			}
		}
		break;

		case 'c':
			search_onCustomDownloadSelected (NULL, search);
		break;

		case 'd':
				search_onDownloadSelected (NULL, search);
		break;

		case 'n':	/* grab toolbar focus */
		case 's':
		case 'a':
		break;

		case 'b':
			search_onAddToBlacklist (NULL, search);
		break;

		default:
			ret = FALSE;
		break;
	}

	last_key = event->keyval;

	return ret;
}





