/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * 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
 */

#define GTK_DISABLE_DEPRECATED

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#ifdef WIN32
#include <windows.h>
#endif

#include "fe-gtk.h"

#include <gtk/gtkcheckmenuitem.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkimagemenuitem.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkmenubar.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkversion.h>
#include <gdk/gdkkeysyms.h>

#include "../common/xchat.h"
#include "../common/xchatc.h"
#include "../common/cfgfiles.h"
#include "../common/outbound.h"
#include "../common/ignore.h"
#include "../common/fe.h"
#include "../common/server.h"
#include "../common/util.h"
#include "xtext.h"
#include "about.h"
#include "ascii.h"
#include "banlist.h"
#include "chanlist.h"
#include "editlist.h"
#include "fkeys.h"
#include "gtkutil.h"
#include "maingui.h"
#include "notifygui.h"
#include "pixmaps.h"
#include "rawlog.h"
#include "palette.h"
#include "plugingui.h"
#include "search.h"
#include "textgui.h"
#include "urlgrab.h"
#include "userlistgui.h"
#include "menu.h"

static GSList *submenu_list;

enum
{
	M_MENU,
	M_NEWMENU,
	M_END,
	M_SEP,
	M_MENUTOG,
	M_MENUD,
	M_MENUSTOCK,
	M_MENUPIX,
	M_MENUSUB
};

struct mymenu
{
	char *text;
	void *callback;
	char *image;
	short type;
	unsigned int state:1;
	unsigned int activate:1;
	guint key;
};


void
goto_url (char *url)
{
#ifdef USE_GNOME
	gnome_url_show (url);
#else
#ifdef WIN32
	ShellExecute (0, "open", url, NULL, NULL, SW_SHOWNORMAL);
#else
	char tbuf[512], *moz;

	/* gnome 2.4+ has this */
	moz = g_find_program_in_path ("gnome-open");
	if (moz)
	{
		snprintf (tbuf, sizeof (tbuf), "%s %s", moz, url);
		g_free (moz);
		xchat_exec (tbuf);
		return;
	}

	moz = g_find_program_in_path ("gnome-moz-remote");
	if (moz)
	{
		snprintf (tbuf, sizeof (tbuf), "%s %s", moz, url);
		g_free (moz);
	} else
	{
		snprintf (tbuf, sizeof (tbuf), "mozilla -remote 'openURL(%s)'", url);
	}
	xchat_exec (tbuf);
#endif
#endif
}

/* execute a userlistbutton/popupmenu command */

static void
nick_command (session * sess, char *cmd)
{
	if (*cmd == '!')
		xchat_exec (cmd + 1);
	else
		handle_command (sess, cmd, TRUE);
}

/* fill in the %a %s %n etc and execute the command */

void
nick_command_parse (session *sess, char *cmd, char *nick, char *allnick)
{
	char *buf;
	char *host = _("Host unknown");
	struct User *user;
	int len;

/*	if (sess->type == SESS_DIALOG)
	{
		buf = (char *)(GTK_ENTRY (sess->gui->topic_entry)->text);
		buf = strrchr (buf, '@');
		if (buf)
			host = buf + 1;
	} else*/
	{
		user = find_name (sess, nick);
		if (user && user->hostname)
			host = strchr (user->hostname, '@') + 1;
	}

	/* this can't overflow, since popup->cmd is only 256 */
	len = strlen (cmd) + strlen (nick) + strlen (allnick) + 512;
	buf = malloc (len);

	auto_insert (buf, len, cmd, 0, 0, allnick, sess->channel, "", host,
						sess->server->nick, nick);

	nick_command (sess, buf);

	free (buf);
}

/* userlist button has been clicked */

void
userlist_button_cb (GtkWidget * button, char *cmd)
{
	int i, num_sel, using_allnicks = FALSE;
	char **nicks, *allnicks;
	char *nick = NULL;
	session *sess;

	sess = current_sess;

	if (strstr (cmd, "%a"))
		using_allnicks = TRUE;

	if (sess->type == SESS_DIALOG)
	{
		/* fake a selection */
		nicks = malloc (sizeof (char *) * 2);
		nicks[0] = sess->channel;
		nicks[1] = NULL;
	} else
	{
		/* find number of selected rows */
		nicks = userlist_selection_list (sess->gui->user_tree, &num_sel);
		if (num_sel < 1)
		{
			nick_command_parse (sess, cmd, "", "");
			return;
		}
	}

	/* create "allnicks" string */
	allnicks = malloc (((NICKLEN + 1) * num_sel) + 1);
	*allnicks = 0;

	i = 0;
	while (nicks[i])
	{
		if (i > 0)
			strcat (allnicks, " ");
		strcat (allnicks, nicks[i]);

		if (!nick)
			nick = nicks[0];

		/* if not using "%a", execute the command once for each nickname */
		if (!using_allnicks)
			nick_command_parse (sess, cmd, nicks[i], "");

		i++;
	}

	if (using_allnicks)
	{
		if (!nick)
			nick = "";
		nick_command_parse (sess, cmd, nick, allnicks);
	}

	if (nicks)
		free (nicks);

	free (allnicks);
}

/* a popup-menu-item has been selected */

static void
popup_menu_cb (GtkWidget * item, char *cmd)
{
	char *nick;

	/* the userdata is set in menu_quick_item() */
	nick = g_object_get_data (G_OBJECT (item), "u");

	if (!nick)	/* userlist popup menu */
	{
		/* treat it just like a userlist button */
		userlist_button_cb (NULL, cmd);
		return;
	}

	if (!current_sess)	/* for url grabber window */
		nick_command_parse (sess_list->data, cmd, nick, nick);
	else
		nick_command_parse (current_sess, cmd, nick, nick);
}

GtkWidget *
menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata,
						int state)
{
	GtkWidget *item;

	item = gtk_check_menu_item_new_with_label (label);
	gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state);
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
	g_signal_connect (G_OBJECT (item), "activate",
							G_CALLBACK (callback), userdata);
	gtk_widget_show (item);

	return item;
}

static GtkWidget *
menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags,
					  gpointer userdata)
{
	GtkWidget *item;
	if (!label)
		item = gtk_menu_item_new ();
	else
		item = gtk_menu_item_new_with_label (label);
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
	g_object_set_data (G_OBJECT (item), "u", userdata);
	if (cmd)
		g_signal_connect (G_OBJECT (item), "activate",
								G_CALLBACK (popup_menu_cb), cmd);
	if (flags & (1 << 0))
		gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
	gtk_widget_show (item);

	return item;
}

static void
menu_quick_item_with_callback (void *callback, char *label, GtkWidget * menu,
										 void *arg)
{
	GtkWidget *item;

	item = gtk_menu_item_new_with_label (label);
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
	g_signal_connect (G_OBJECT (item), "activate",
							G_CALLBACK (callback), arg);
	gtk_widget_show (item);
}

static GtkWidget *
menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret)
{
	GtkWidget *sub_menu;
	GtkWidget *sub_item;

	if (!name)
		return menu;

	/* Code to add a submenu */
	sub_menu = gtk_menu_new ();
	sub_item = gtk_menu_item_new_with_label (name);
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), sub_item);
	gtk_widget_show (sub_item);
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub_item), sub_menu);

	if (sub_item_ret)
		*sub_item_ret = sub_item;

	/* We create a new element in the list */
	submenu_list = g_slist_prepend (submenu_list, sub_menu);
	return sub_menu;
}

static GtkWidget *
menu_quick_endsub ()
{
	/* Just delete the first element in the linked list pointed to by first */
	if (submenu_list)
		submenu_list = g_slist_remove (submenu_list, submenu_list->data);

	if (submenu_list)
		return (submenu_list->data);
	else
		return NULL;
}

static void
toggle_cb (GtkWidget *item, char *pref_name)
{
	char buf[256];

	if (GTK_CHECK_MENU_ITEM (item)->active)
		snprintf (buf, sizeof (buf), "set %s 1", pref_name);
	else
		snprintf (buf, sizeof (buf), "set %s 0", pref_name);

	handle_command (current_sess, buf, FALSE);
}

static int
is_in_path (char *cmd)
{
	char *prog = strdup (cmd + 1);	/* 1st char is "!" */
	char *space, *path, *orig;

	orig = prog; /* save for free()ing */
	/* special-case these default entries. */
	/*                  123456789012345678 */
	if (strncmp (prog, "gnome-terminal -x ", 18) == 0)
	/* don't check for gnome-terminal, but the thing it's executing! */
		prog += 18;

	space = strchr (prog, ' ');	/* this isn't 100% but good enuf */
	if (space)
		*space = 0;

	path = g_find_program_in_path (prog);
	if (path)
	{
		g_free (path);
		g_free (orig);
		return 1;
	}

	g_free (orig);
	return 0;
}

/* append items to "menu" using the (struct popup*) list provided */

void
menu_create (GtkWidget *menu, GSList *list, char *target, int check_path)
{
	struct popup *pop;
	GtkWidget *tempmenu = menu, *subitem = NULL;
	int childcount = 0;

	submenu_list = g_slist_prepend (0, menu);
	while (list)
	{
		pop = (struct popup *) list->data;

		if (!strncasecmp (pop->name, "SUB", 3))
		{
			childcount = 0;
			tempmenu = menu_quick_sub (pop->cmd, tempmenu, &subitem);

		} else if (!strncasecmp (pop->name, "TOGGLE", 6))
		{
			childcount++;
			menu_toggle_item (pop->name + 7, tempmenu, toggle_cb, pop->cmd,
									cfg_get_bool (pop->cmd));

		} else if (!strncasecmp (pop->name, "ENDSUB", 6))
		{
			/* empty sub menu due to no programs in PATH? */
			if (check_path && childcount < 1)
				gtk_widget_destroy (subitem);
			subitem = NULL;

			if (tempmenu != menu)
				tempmenu = menu_quick_endsub ();
			/* If we get here and tempmenu equals menu that means we havent got any submenus to exit from */

		} else if (!strncasecmp (pop->name, "SEP", 3))
		{
			menu_quick_item (0, 0, tempmenu, 1, 0);

		} else
		{
			if (!check_path || pop->cmd[0] != '!')
			{
				menu_quick_item (pop->cmd, pop->name, tempmenu, 0, target);
			/* check if the program is in path, if not, leave it out! */
			} else if (is_in_path (pop->cmd))
			{
				childcount++;
				menu_quick_item (pop->cmd, pop->name, tempmenu, 0, target);
			}
		}

		list = list->next;
	}

	/* Let's clean up the linked list from mem */
	while (submenu_list)
		submenu_list = g_slist_remove (submenu_list, submenu_list->data);
}

static void
menu_destroy (GtkObject *object, gpointer objtounref)
{
	gtk_widget_destroy (GTK_WIDGET (object));
	if (objtounref)
		g_object_unref (G_OBJECT (objtounref));
}

static void
menu_popup (GtkWidget *menu, GdkEventButton *event, gpointer objtounref)
{
#if (GTK_MAJOR_VERSION != 2) || (GTK_MINOR_VERSION != 0)
	if (event && event->window)
		gtk_menu_set_screen (GTK_MENU (menu), gdk_drawable_get_screen (event->window));
#endif

	g_signal_connect (G_OBJECT (menu), "selection-done",
							G_CALLBACK (menu_destroy), objtounref);
	if (event == NULL)
		gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, 0);
	else
		gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
							 0, event->time);
}

static char *str_copy = 0;		/* for all pop-up menus */

void
menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
{
	char buf[256];
	struct User *user;
	GtkWidget *wid, *submenu, *menu = gtk_menu_new ();

	if (str_copy)
		free (str_copy);
	str_copy = strdup (nick);

	submenu_list = 0;	/* first time though, might not be 0 */

	/* more than 1 nick selected? */
	if (num_sel > 1)
	{
		snprintf (buf, sizeof (buf), "%d nicks selected.", num_sel);
		menu_quick_item (0, buf, menu, 0, 0);
		menu_quick_item (0, 0, menu, 1, 0);
	} else
	{
		user = find_name_global (current_sess->server, nick);
		if (user)
		{
			submenu = menu_quick_sub (nick, menu, NULL);

			snprintf (buf, sizeof (buf), _("User: %s"),
						user->hostname ? user->hostname : _("Unknown"));
			menu_quick_item (0, buf, submenu, 0, 0);

			snprintf (buf, sizeof (buf), _("Country: %s"),
						user->hostname ? country(user->hostname) : _("Unknown"));
			menu_quick_item (0, buf, submenu, 0, 0);

			snprintf (buf, sizeof (buf), _("Realname: %s"),
						user->realname ? user->realname : _("Unknown"));
			menu_quick_item (0, buf, submenu, 0, 0);

			snprintf (buf, sizeof (buf), _("Server: %s"),
						user->servername ? user->servername : _("Unknown"));
			menu_quick_item (0, buf, submenu, 0, 0);

			snprintf (buf, sizeof (buf), _("Last Msg: %s"),
						user->lasttalk ? ctime (&(user->lasttalk)) : _("Unknown"));
			if (user->lasttalk)
				buf[strlen (buf) - 1] = 0;
			wid = menu_quick_item (0, buf, submenu, 0, 0);

			gtk_label_set_justify (GTK_LABEL (GTK_BIN (wid)->child), GTK_JUSTIFY_LEFT);
			menu_quick_endsub ();
			menu_quick_item (0, 0, menu, 1, 0);
		}
	}

	if (num_sel > 1)
		menu_create (menu, popup_list, NULL, FALSE);
	else
		menu_create (menu, popup_list, str_copy, FALSE);
	menu_popup (menu, event, NULL);
}

static void
menu_showhide (void)
{
	session *sess;
	GSList *list;

	list = sess_list;
	while (list)
	{
		sess = list->data;

		if (sess->gui->menu)
		{
			if (prefs.hidemenu)
				gtk_widget_hide (sess->gui->menu);
			else
				gtk_widget_show (sess->gui->menu);
		}

		list = list->next;
	}
}

static void
menu_middle_cb (GtkWidget *item, gpointer userdata)
{
	switch (GPOINTER_TO_INT (userdata))
	{
	case 0:
		if (prefs.hidemenu)
			prefs.hidemenu = 0;
		else
			prefs.hidemenu = 1;
		menu_showhide ();
		break;
	case 1:
		mg_topic_showhide (current_sess);
		break;
	case 2:
		prefs.hideuserlist = !prefs.hideuserlist;
		mg_userlist_showhide (current_sess, !prefs.hideuserlist);
		break;
	case 3:
		prefs.chanmodebuttons = !prefs.chanmodebuttons;
		mg_chanmodebuttons_showhide (current_sess, prefs.chanmodebuttons);
		break;
	case 4:
		prefs.userlistbuttons = !prefs.userlistbuttons;
		if (prefs.userlistbuttons)
			gtk_widget_show (current_sess->gui->button_box);
		else
			gtk_widget_hide (current_sess->gui->button_box);
	}
}

void
menu_middlemenu (session *sess, GdkEventButton *event)
{
	GtkWidget *menu, *away, *user, *item;
	GtkAccelGroup *accel_group;

	accel_group = gtk_accel_group_new ();
	menu = menu_create_main (accel_group, FALSE, sess->server->is_away, !sess->gui->is_tab, &away, &user);

	menu_quick_item (0, 0, menu, 1, 0);	/* sep */

	menu_toggle_item (_("Menu Bar"), menu, menu_middle_cb, 0, !prefs.hidemenu);
	menu_toggle_item (_("Topic Bar"), menu, menu_middle_cb,
							GINT_TO_POINTER (1), prefs.topicbar);

	if (!prefs.paned_userlist)
		menu_toggle_item (_("User List"), menu, menu_middle_cb,
								GINT_TO_POINTER (2), !prefs.hideuserlist);

	item = menu_toggle_item (_("Mode Buttons"), menu, menu_middle_cb,
									GINT_TO_POINTER (3),
									prefs.topicbar ? prefs.chanmodebuttons : 0);
	if (!prefs.topicbar)
		gtk_widget_set_sensitive (item, FALSE);

	menu_toggle_item (_("User List Buttons"), menu, menu_middle_cb,
							GINT_TO_POINTER (4), prefs.userlistbuttons);

	menu_popup (menu, event, accel_group);
}

#ifdef WIN32
static void
open_url_cb (GtkWidget *item, char *url)
{
	goto_url (url);
}
#endif

static void
copy_to_clipboard_cb (GtkWidget *item, char *url)
{
	gtkutil_copy_to_clipboard (item, NULL, url);
}

void
menu_urlmenu (GdkEventButton *event, char *url)
{
	GtkWidget *menu;
	char *tmp;

	if (str_copy)
		free (str_copy);

#if 0
	/* replace all commas with %2c */
	str_copy = malloc ((strlen (url) * 3) + 1);
	i = 0;
	while (*url)
	{
		if (*url == ',')
		{
			str_copy[i++] = '%';
			str_copy[i++] = '2';
			str_copy[i] = 'c';
#ifdef WIN32
		} else if (*url == '\\')
		{
			str_copy[i++] = '\\';
			str_copy[i] = '\\';
#endif
		} else
			str_copy[i] = *url;
		i++;
		url++;
	}
	str_copy[i] = 0;
#else
	str_copy = strdup (url);
#endif

	menu = gtk_menu_new ();
	if (strlen (str_copy) > 51)
	{
		tmp = strdup (str_copy);
		tmp[47] = tmp[48] = tmp[49] = '.';
		tmp[50] = 0;
		menu_quick_item (0, tmp, menu, 1, 0);
		free (tmp);
	} else
	{
		menu_quick_item (0, str_copy, menu, 1, 0);
	}
	menu_quick_item (0, 0, menu, 1, 0);

	menu_quick_item_with_callback (copy_to_clipboard_cb, _("Copy selected URL"), menu, str_copy);
#ifdef WIN32
	menu_quick_item_with_callback (open_url_cb, "Open URL", menu, str_copy);
#endif

	menu_create (menu, urlhandler_list, str_copy, TRUE);
	menu_popup (menu, event, NULL);
}

static void
menu_chan_cycle (GtkWidget * menu, char *chan)
{
	if (current_sess)
		handle_command (current_sess, "cycle", FALSE);
}

static void
menu_chan_part (GtkWidget * menu, char *chan)
{
	char tbuf[256];

	if (current_sess)
	{
		snprintf (tbuf, sizeof tbuf, "part %s", chan);
		handle_command (current_sess, tbuf, FALSE);
	}
}

static void
menu_chan_join (GtkWidget * menu, char *chan)
{
	char tbuf[256];

	if (current_sess)
	{
		snprintf (tbuf, sizeof tbuf, "join %s", chan);
		handle_command (current_sess, tbuf, FALSE);
	}
}

void
menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan)
{
	GtkWidget *menu;
	int is_joined = FALSE;

	if (find_channel (sess->server, chan))
		is_joined = TRUE;

	if (str_copy)
		free (str_copy);
	str_copy = strdup (chan);

	menu = gtk_menu_new ();

	menu_quick_item (0, chan, menu, 1, str_copy);
	menu_quick_item (0, 0, menu, 1, str_copy);

	if (!is_joined)
		menu_quick_item_with_callback (menu_chan_join, _("Join Channel"), menu,
												 str_copy);
	else
	{
		menu_quick_item_with_callback (menu_chan_part, _("Part Channel"), menu,
												 str_copy);
		menu_quick_item_with_callback (menu_chan_cycle, _("Cycle Channel"), menu,
												 str_copy);
	}

	menu_popup (menu, event, NULL);
}

static void
menu_open_server_list (GtkWidget *wid, gpointer none)
{
	fe_serverlist_open (current_sess);
}

static void
menu_settings (GtkWidget * wid, gpointer none)
{
	extern void setup_open (void);
	setup_open ();
}

static void
menu_usermenu (void)
{
	editlist_gui_open (usermenu_list, _("X-Chat: User menu"), "usermenu",
							 "usermenu.conf", 0);
}

static void
usermenu_create (GtkWidget *menu)
{
	menu_create (menu, usermenu_list, "", FALSE);
	menu_quick_item (0, 0, menu, 1, 0);	/* sep */
	menu_quick_item_with_callback (menu_usermenu, _("Edit This Menu..."), menu, 0);
}

static void
usermenu_destroy (GtkWidget * menu)
{
	GList *items = ((GtkMenuShell *) menu)->children;
	GList *next;

	while (items)
	{
		next = items->next;
		gtk_widget_destroy (items->data);
		items = next;
	}
}

void
usermenu_update (void)
{
	int done_main = FALSE;
	GSList *list = sess_list;
	session *sess;

	while (list)
	{
		sess = list->data;
		if (sess->gui->is_tab)
		{
			if (!done_main)
			{
				if (sess->gui->user_menu)
				{
					usermenu_destroy (sess->gui->user_menu);
					usermenu_create (sess->gui->user_menu);
					done_main = TRUE;
				}
			}
		} else
		{
			usermenu_destroy (sess->gui->user_menu);
			usermenu_create (sess->gui->user_menu);
		}
		list = list->next;
	}
}

static void
menu_newserver_window (GtkWidget * wid, gpointer none)
{
	int old = prefs.tabchannels;

	prefs.tabchannels = 0;
	new_ircwindow (NULL, NULL, SESS_SERVER, 0);
	prefs.tabchannels = old;
}

static void
menu_newchannel_window (GtkWidget * wid, gpointer none)
{
	int old = prefs.tabchannels;

	prefs.tabchannels = 0;
	new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0);
	prefs.tabchannels = old;
}

static void
menu_newserver_tab (GtkWidget * wid, gpointer none)
{
	int old = prefs.tabchannels;
	int oldf = prefs.newtabstofront;

	prefs.tabchannels = 1;
	/* force focus if setting is "only requested tabs" */
	if (prefs.newtabstofront == 2)
		prefs.newtabstofront = 1;
	new_ircwindow (NULL, NULL, SESS_SERVER, 0);
	prefs.tabchannels = old;
	prefs.newtabstofront = oldf;
}

static void
menu_newchannel_tab (GtkWidget * wid, gpointer none)
{
	int old = prefs.tabchannels;

	prefs.tabchannels = 1;
	new_ircwindow (current_sess->server, NULL, SESS_CHANNEL, 0);
	prefs.tabchannels = old;
}

static void
menu_rawlog (GtkWidget * wid, gpointer none)
{
	open_rawlog (current_sess->server);
}

static void
menu_autodccsend (GtkWidget * wid, gpointer none)
{
	prefs.autodccsend = !prefs.autodccsend;
#ifndef WIN32
	if (prefs.autodccsend)
	{
		if (!strcmp ((char *)g_get_home_dir (), prefs.dccdir))
		{
			gtkutil_simpledialog (_("*WARNING*\n"
										 "Auto accepting DCC to your home directory\n"
										 "can be dangerous and is exploitable. Eg:\n"
										 "Someone could send you a .bash_profile"));
		}
	}
#endif
}

static void
menu_detach (GtkWidget * wid, gpointer none)
{
	mg_link_cb (NULL, NULL);
}

static void
menu_close (GtkWidget * wid, gpointer none)
{
	mg_x_click_cb (NULL, NULL);
}

static void
menu_search ()
{
	search_open (current_sess);
}

static void
menu_resetmarker (GtkWidget * wid, gpointer none)
{
	gtk_xtext_reset_marker_pos (GTK_XTEXT (current_sess->gui->xtext));
}

static void
menu_flushbuffer (GtkWidget * wid, gpointer none)
{
	fe_text_clear (current_sess);
}

static void
savebuffer_req_done (session *sess, char *file)
{
	int fh;

	if (!file)
		return;

	fh = open (file, O_TRUNC | O_WRONLY | O_CREAT, 0600);
	if (fh != -1)
	{
		gtk_xtext_save (GTK_XTEXT (sess->gui->xtext), fh);
		close (fh);
	}
}

static void
menu_savebuffer (GtkWidget * wid, gpointer none)
{
	gtkutil_file_req (_("Select an output filename"), savebuffer_req_done,
							current_sess, NULL, FRF_WRITE);
}

static void
menu_wallops (GtkWidget * wid, gpointer none)
{
	char mode[3];
	server *serv = current_sess->server;
	prefs.wallops = !prefs.wallops;
	if (serv->connected)
	{
		mode[1] = 'w';
		mode[2] = '\0';
		if (prefs.wallops)
			mode[0] = '+';
		else
			mode[0] = '-';
		serv->p_mode (serv, serv->nick, mode);
	}
}

static void
menu_servernotice (GtkWidget * wid, gpointer none)
{
	char mode[3];
	server *serv = current_sess->server;
	prefs.servernotice = !prefs.servernotice;
	if (serv->connected)
	{
		mode[1] = 's';
		mode[2] = '\0';
		if (prefs.servernotice)
			mode[0] = '+';
		else
			mode[0] = '-';
		serv->p_mode (serv, serv->nick, mode);
	}
}

static void
menu_away (GtkWidget * wid, gpointer none)
{
	handle_command (current_sess, "away", FALSE);
}

static void
menu_invisible (GtkWidget * wid, gpointer none)
{
	char mode[3];
	server *serv = current_sess->server;
	prefs.invisible = !prefs.invisible;
	if (current_sess->server->connected)
	{
		mode[1] = 'i';
		mode[2] = '\0';
		if (prefs.invisible)
			mode[0] = '+';
		else
			mode[0] = '-';
		serv->p_mode (serv, serv->nick, mode);
	}
}

#if 0
static void
menu_savedefault (GtkWidget * wid, gpointer none)
{
	palette_save ();
	if (save_config ())
		gtkutil_simpledialog (_("Settings saved."));
}
#endif

static void
menu_chanlist (GtkWidget * wid, gpointer none)
{
	chanlist_opengui (current_sess->server);
}

static void
menu_banlist (GtkWidget * wid, gpointer none)
{
	banlist_opengui (current_sess);
}

#ifdef USE_PLUGIN

static void
menu_loadplugin (void)
{
	plugingui_load ();
}

static void
menu_pluginlist (void)
{
	plugingui_open ();
}

#else

#define menu_pluginlist 0
#define menu_loadplugin 0

#endif

#define usercommands_help  _("User Commands - Special codes:\n\n"\
                           "%c  =  current channel\n"\
									"%m  =  machine info\n"\
                           "%n  =  your nick\n"\
									"%t  =  time/date\n"\
                           "%v  =  xchat version\n"\
                           "%2  =  word 2\n"\
                           "%3  =  word 3\n"\
                           "&2  =  word 2 to the end of line\n"\
                           "&3  =  word 3 to the end of line\n\n"\
                           "eg:\n"\
                           "/cmd john hello\n\n"\
                           "%2 would be \042john\042\n"\
                           "&2 would be \042john hello\042.")

#define ulbutton_help       _("Userlist Buttons - Special codes:\n\n"\
                           "%a  =  all selected nicks\n"\
                           "%c  =  current channel\n"\
                           "%h  =  selected nick's hostname\n"\
									"%m  =  machine info\n"\
                           "%n  =  your nick\n"\
                           "%s  =  selected nick\n"\
									"%t  =  time/date\n")

#define dlgbutton_help      _("Dialog Buttons - Special codes:\n\n"\
                           "%a  =  all selected nicks\n"\
                           "%c  =  current channel\n"\
                           "%h  =  selected nick's hostname\n"\
									"%m  =  machine info\n"\
                           "%n  =  your nick\n"\
                           "%s  =  selected nick\n"\
									"%t  =  time/date\n")

#define ctcp_help          _("CTCP Replies - Special codes:\n\n"\
                           "%d  =  data (the whole ctcp)\n"\
									"%m  =  machine info\n"\
                           "%s  =  nick who sent the ctcp\n"\
                           "%t  =  time/date\n"\
                           "%2  =  word 2\n"\
                           "%3  =  word 3\n"\
                           "&2  =  word 2 to the end of line\n"\
                           "&3  =  word 3 to the end of line\n\n")

#define url_help           _("URL Handlers - Special codes:\n\n"\
                           "%s  =  the URL string\n\n"\
                           "Putting a ! infront of the command\n"\
                           "indicates it should be sent to a\n"\
                           "shell instead of X-Chat")

static void
menu_usercommands (void)
{
	editlist_gui_open (command_list, _("X-Chat: User Defined Commands"),
							 "commands", "commands.conf", usercommands_help);
}

static void
menu_ulpopup (void)
{
	editlist_gui_open (popup_list, _("X-Chat: Userlist Popup menu"), "popup",
							 "popup.conf", ulbutton_help);
}

static void
menu_rpopup (void)
{
	editlist_gui_open (replace_list, _("X-Chat: Replace"), "replace",
							 "replace.conf", 0);
}

static void
menu_urlhandlers (void)
{
	editlist_gui_open (urlhandler_list, _("X-Chat: URL Handlers"), "urlhandlers",
							 "urlhandlers.conf", url_help);
}

static void
menu_evtpopup (void)
{
	pevent_dialog_show ();
}

static void
menu_keypopup (void)
{
	key_dialog_show ();
}

static void
menu_ulbuttons (void)
{
	editlist_gui_open (button_list, _("X-Chat: Userlist buttons"), "buttons",
							 "buttons.conf", ulbutton_help);
}

static void
menu_dlgbuttons (void)
{
	editlist_gui_open (dlgbutton_list, _("X-Chat: Dialog buttons"), "dlgbuttons",
							 "dlgbuttons.conf", dlgbutton_help);
}

static void
menu_ctcpguiopen (void)
{
	editlist_gui_open (ctcp_list, _("X-Chat: CTCP Replies"), "ctcpreply",
							 "ctcpreply.conf", ctcp_help);
}

#if 0
static void
menu_reload (void)
{
	char *buf = malloc (strlen (default_file ()) + 12);
	load_config ();
	sprintf (buf, "%s reloaded.", default_file ());
	fe_message (buf, FALSE);
	free (buf);
}
#endif

static void
menu_autorejoin (GtkWidget *wid, gpointer none)
{
	prefs.autorejoin = !prefs.autorejoin;
}

static void
menu_autoreconnect (GtkWidget *wid, gpointer none)
{
	prefs.autoreconnect = !prefs.autoreconnect;
}

static void
menu_autoreconnectonfail (GtkWidget *wid, gpointer none)
{
	prefs.autoreconnectonfail = !prefs.autoreconnectonfail;
}

static void
menu_autodialog (GtkWidget *wid, gpointer none)
{
	if (GTK_CHECK_MENU_ITEM (wid)->active)
		prefs.autodialog = 1;
	else
		prefs.autodialog = 0;
}

static void
menu_autodccchat (GtkWidget *wid, gpointer none)
{
	prefs.autodccchat = !prefs.autodccchat;
}

#if 0
static void
menu_saveexit (GtkWidget *wid, gpointer none)
{
	prefs.autosave = !prefs.autosave;
}
#endif

static void
menu_docs (GtkWidget *wid, gpointer none)
{
	goto_url ("http://xchat.org/docs/");
}

/*static void
menu_webpage (GtkWidget *wid, gpointer none)
{
	goto_url ("http://xchat.org");
}*/

static void
menu_dcc_recv_win (GtkWidget *wid, gpointer none)
{
	fe_dcc_open_recv_win (FALSE);
}

static void
menu_dcc_send_win (GtkWidget *wid, gpointer none)
{
	fe_dcc_open_send_win (FALSE);
}

static void
menu_dcc_chat_win (GtkWidget *wid, gpointer none)
{
	fe_dcc_open_chat_win (FALSE);
}

static struct mymenu mymenu[] = {
	{N_("_X-Chat"), 0, 0, M_NEWMENU, 0, 1},
	{N_("Server List..."), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 1, GDK_s},
	{0, 0, 0, M_SEP, 0, 0},

	{N_("New"), 0, GTK_STOCK_NEW, M_MENUSUB, 0, 1},
	{N_("Server Tab..."), menu_newserver_tab, 0, M_MENU, 0, 1, GDK_t},
	{N_("Channel Tab..."), menu_newchannel_tab, 0, M_MENU, 0, 1},
	{N_("Server Window..."), menu_newserver_window, 0, M_MENU, 0, 1},
	{N_("Channel Window..."), menu_newchannel_window, 0, M_MENU, 0, 1},
	{0, 0, 0, M_END, 0, 0},
	{0, 0, 0, M_SEP, 0, 0},

#ifdef USE_PLUGIN
	{N_("Load Plugin or Script..."), menu_loadplugin, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 1},
#else
	{N_("Load Plugin or Script..."), 0, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0},
#endif
	{0, 0, 0, M_SEP, 0, 0},	/* 11 */
#ifdef USE_ZVT
	{N_("New Shell Tab..."), menu_newshell_tab, 0, M_MENU, 0, 1},
	{0, 0, 0, M_SEP, 0, 0},
#define menuoffset 0
#else
#define menuoffset 2
#endif
	{0, menu_detach, GTK_STOCK_REDO, M_MENUSTOCK, 0, 1, GDK_I},	/* 14 */
	{N_("Close Tab"), menu_close, GTK_STOCK_CLOSE, M_MENUSTOCK, 0, 1, GDK_w},
	{0, 0, 0, M_SEP, 0, 0},
	{N_("Quit"), mg_safe_quit, GTK_STOCK_QUIT, M_MENUSTOCK, 0, 1, GDK_q},	/* 17 */

	{N_("_IRC"), 0, 0, M_NEWMENU, 0, 1},
	{N_("Invisible"), menu_invisible, 0, M_MENUTOG, 1, 1},
	{N_("Receive Wallops"), menu_wallops, 0, M_MENUTOG, 1, 1},
	{N_("Receive Server Notices"), menu_servernotice, 0, M_MENUTOG, 1, 1},
	{0, 0, 0, M_SEP, 0, 0},
	{N_("Marked Away"), menu_away, 0, M_MENUTOG, 0, 1, GDK_a},
	{0, 0, 0, M_SEP, 0, 0},														/* 24 */
	{N_("Auto Rejoin when Kicked"), menu_autorejoin, 0, M_MENUTOG, 0, 1},
	{N_("Auto Reconnect to Server"), menu_autoreconnect, 0, M_MENUTOG, 0, 1},
	{N_("Never-give-up ReConnect"), menu_autoreconnectonfail, 0, M_MENUTOG, 0, 1},
	{0, 0, 0, M_SEP, 0, 0},														/* 28 */
	{N_("Auto Open Dialog Windows"), menu_autodialog, 0, M_MENUTOG, 0, 1},
	{N_("Auto Accept Direct Chat"), menu_autodccchat, 0, M_MENUTOG, 0, 1},
	{N_("Auto Accept Files"), menu_autodccsend, 0, M_MENUTOG, 0, 1},

	{N_("_Server"), (void *) -1, 0, M_NEWMENU, 0, 1},	/* 32 */

	{N_("S_ettings"), 0, 0, M_NEWMENU, 0, 1},	/* 33 */
	{N_("Preferences..."), menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 1},

	{N_("Advanced"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 1},
	{N_("Auto Replace..."), menu_rpopup, 0, M_MENU, 0, 1},
	{N_("CTCP Replies..."), menu_ctcpguiopen, 0, M_MENU, 0, 1},
	{N_("Dialog Buttons..."), menu_dlgbuttons, 0, M_MENU, 0, 1},
	{N_("Keyboard Shortcuts..."), menu_keypopup, 0, M_MENU, 0, 1},
	{N_("Text Events..."), menu_evtpopup, 0, M_MENU, 0, 1},
	{N_("URL Handlers..."), menu_urlhandlers, 0, M_MENU, 0, 1},
	{N_("User Commands..."), menu_usercommands, 0, M_MENU, 0, 1},
	{N_("Userlist Buttons..."), menu_ulbuttons, 0, M_MENU, 0, 1},
	{N_("Userlist Popup..."), menu_ulpopup, 0, M_MENU, 0, 1},
	{0, 0, 0, M_END, 0, 0},		/* 45 */

#if 0
	{0, 0, 0, M_SEP, 0, 0},	/* 56 */
	{N_("Reload Settings"), menu_reload, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 1},
	{0, 0, 0, M_SEP, 0, 0},
	{N_("Save Settings now"), menu_savedefault, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 1},
	{N_("Save Settings on exit"), menu_saveexit, 0, M_MENUTOG, 1, 1},
#endif

	{N_("_Window"), 0, 0, M_NEWMENU, 0, 1},
	{N_("Ban List..."), menu_banlist, 0, M_MENU, 0, 1},
	{N_("Channel List..."), menu_chanlist, 0, M_MENU, 0, 1},
	{N_("Character Chart..."), ascii_open, 0, M_MENU, 0, 1},
	{N_("Direct Chat..."), menu_dcc_chat_win, 0, M_MENU, 0, 1},
	{N_("File Receive..."), menu_dcc_recv_win, 0, M_MENU, 0, 1},
	{N_("File Send..."), menu_dcc_send_win, 0, M_MENU, 0, 1},
	{N_("Ignore List..."), ignore_gui_open, 0, M_MENU, 0, 1},
	{N_("Notify List..."), notify_opengui, 0, M_MENU, 0, 1},
	{N_("Plugins and Scripts..."), menu_pluginlist, 0, M_MENU, 0, 1},
	{N_("Raw Log..."), menu_rawlog, 0, M_MENU, 0, 1},	/* 51 */
	{N_("URL Grabber..."), url_opengui, 0, M_MENU, 0, 1},
	{0, 0, 0, M_SEP, 0, 0},
	{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENU, 0, 1, GDK_m},
	{N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 1, GDK_l},
	{N_("Search Text..."), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 1, GDK_f},
	{N_("Save Text..."), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 1},

	{N_("_Help"), 0, 0, M_NEWMENU, 0, 1},	/* 62 */
	{N_("_Contents"), menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 1, GDK_F1},
#ifdef GTK_STOCK_ABOUT
	{N_("_About"), menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 1},
#else
	{N_("_About"), menu_about, (char *)&pix_about, M_MENUPIX, 0, 1},
#endif

	{0, 0, 0, M_END, 0, 0},
};

GtkWidget *
create_icon_menu (char *labeltext, void *stock_name, int is_stock)
{
	GtkWidget *item, *img;

	if (is_stock)
		img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU);
	else
		img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name));
	item = gtk_image_menu_item_new_with_mnemonic (labeltext);
	gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img);
	gtk_widget_show (img);

	return item;
}

#if GTK_CHECK_VERSION(2,4,0)

/* Override the default GTK2.4 handler, which would make menu
   bindings not work when the menu-bar is hidden. */
static gboolean
menu_canacaccel (GtkWidget *widget, guint signal_id, gpointer user_data)
{
	/* GTK2.2 behaviour */
	return GTK_WIDGET_IS_SENSITIVE (widget);
}

#endif

GtkWidget *
menu_create_main (void *accel_group, int bar, int away, int toplevel,
						GtkWidget **away_item_ret, GtkWidget **user_menu_ret)
{
	int i = 0;
	GtkWidget *item;
	GtkWidget *menu = 0;
	GtkWidget *menu_item = 0;
	GtkWidget *menu_bar;
	GtkWidget *usermenu = 0;
	GtkWidget *submenu = 0;
	int close_mask = GDK_CONTROL_MASK;
	char *key_theme = NULL;
	GtkSettings *settings;

	if (bar)
		menu_bar = gtk_menu_bar_new ();
	else
		menu_bar = gtk_menu_new ();

#if GTK_CHECK_VERSION(2,4,0)
	g_signal_connect (G_OBJECT (menu_bar), "can-activate-accel",
							G_CALLBACK (menu_canacaccel), 0);
#endif

	mymenu[19-menuoffset].state = prefs.invisible;
	mymenu[20-menuoffset].state = prefs.wallops;
	mymenu[21-menuoffset].state = prefs.servernotice;
	mymenu[23-menuoffset].state = away;
	mymenu[25-menuoffset].state = prefs.autorejoin;
	mymenu[26-menuoffset].state = prefs.autoreconnect;
	mymenu[27-menuoffset].state = prefs.autoreconnectonfail;
	mymenu[29-menuoffset].state = prefs.autodialog;
	mymenu[30-menuoffset].state = prefs.autodccchat;
	mymenu[31-menuoffset].state = prefs.autodccsend;
	/*mymenu[60-menuoffset].state = prefs.autosave;*/

	/* change Close binding to ctrl-shift-w when using emacs keys */
	settings = gtk_widget_get_settings (menu_bar);
	if (settings)
	{
		g_object_get (settings, "gtk-key-theme-name", &key_theme, NULL);
		if (key_theme)
		{
			if (!strcasecmp (key_theme, "Emacs"))
				close_mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK;
			g_free (key_theme);
		}
	}

	if (!toplevel)
		mymenu[14-menuoffset].text = _("Detach Tab");
	else
		mymenu[14-menuoffset].text = _("Attach Tab");

	while (1)
	{
		switch (mymenu[i].type)
		{
		case M_NEWMENU:
			if (menu)
				gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
			menu = gtk_menu_new ();
			if (mymenu[i].callback == (void *) -1)
				usermenu = menu;
			menu_item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
			gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item);
			gtk_widget_show (menu_item);
			break;

		case M_MENUPIX:
			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, FALSE);
			goto normalitem;

		case M_MENUSTOCK:
			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE);
			goto normalitem;

		case M_MENU:
			item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
normalitem:
			if (mymenu[i].key != 0)
				gtk_widget_add_accelerator (item, "activate", accel_group,
										mymenu[i].key,
										mymenu[i].key == GDK_F1 ? 0 :
										mymenu[i].key == GDK_w ? close_mask :
										GDK_CONTROL_MASK,
										GTK_ACCEL_VISIBLE);
			if (mymenu[i].callback)
				g_signal_connect (G_OBJECT (item), "activate",
										G_CALLBACK (mymenu[i].callback), 0);
			if (submenu)
				gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
			else
				gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
			gtk_widget_show (item);
			gtk_widget_set_sensitive (item, mymenu[i].activate);
			break;

		case M_MENUTOG:
			item = gtk_check_menu_item_new_with_label (_(mymenu[i].text));
			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
													 mymenu[i].state);
			if (mymenu[i].key != 0)
				gtk_widget_add_accelerator (item, "activate", accel_group,
									mymenu[i].key, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
			if (mymenu[i].callback)
				g_signal_connect (G_OBJECT (item), "toggled",
										G_CALLBACK (mymenu[i].callback), 0);
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
			gtk_widget_show (item);
			gtk_widget_set_sensitive (item, mymenu[i].activate);
			if (bar && i == 23 - menuoffset)
				*away_item_ret = item;
			break;

		case M_SEP:
			item = gtk_menu_item_new ();
			gtk_widget_set_sensitive (item, FALSE);
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
			gtk_widget_show (item);
			break;

		case M_MENUSUB:
			submenu = gtk_menu_new ();
			item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE);
			gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
			gtk_widget_show (item);
			break;

		case M_END:
			if (!submenu)
			{
				if (menu)
					gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
				if (usermenu)
					usermenu_create (usermenu);
				if (bar)
					*user_menu_ret = usermenu;
				return (menu_bar);
			}
			submenu = 0;
		}
		i++;
	}
}
