summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--share/doc/readme.md2
-rw-r--r--src/common/inbound.c10
-rw-r--r--src/common/servlist.c88
-rw-r--r--src/common/servlist.h14
-rw-r--r--src/fe-gtk/servlistgui.c209
6 files changed, 248 insertions, 77 deletions
diff --git a/configure.ac b/configure.ac
index 910565e9..56a7abe1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,7 +184,7 @@ dnl *********************************************************************
 dnl ** GLIB *************************************************************
 dnl *********************************************************************
 
-AM_PATH_GLIB_2_0(2.14.0, glib=yes, glib=no)
+AM_PATH_GLIB_2_0(2.28.0, glib=yes, glib=no)
 if test "$glib" = no; then
 	AC_MSG_ERROR(Cannot find GLib!)
 fi
diff --git a/share/doc/readme.md b/share/doc/readme.md
index 9d9cc91c..dc66e0ac 100644
--- a/share/doc/readme.md
+++ b/share/doc/readme.md
@@ -22,7 +22,7 @@ in general. HexChat runs on most BSD and POSIX compliant operating systems.
 ## Requirements:
 
  * GTK+ 2.24
- * GLib 2.14
+ * GLib 2.28
 
 HexChat is known to work on, at least:
 
diff --git a/src/common/inbound.c b/src/common/inbound.c
index 2383955e..4f23403f 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -1384,6 +1384,8 @@ inbound_nickserv_login (server *serv)
 void
 inbound_login_end (session *sess, char *text)
 {
+	GSList *cmdlist;
+	commandentry *cmd;
 	server *serv = sess->server;
 
 	if (!serv->end_of_motd)
@@ -1398,9 +1400,13 @@ inbound_login_end (session *sess, char *text)
 		if (serv->network)
 		{
 			/* there may be more than 1, separated by \n */
-			if (((ircnet *)serv->network)->command)
+
+			cmdlist = ((ircnet *)serv->network)->commandlist;
+			while (cmdlist)
 			{
-				token_foreach (((ircnet *)serv->network)->command, '\n', inbound_exec_eom_cmd, sess);
+				cmd = cmdlist->data;
+				inbound_exec_eom_cmd (cmd->command, sess);
+				cmdlist = cmdlist->next;
 			}
 
 			/* send nickserv password */
diff --git a/src/common/servlist.c b/src/common/servlist.c
index f30dcf48..ed822925 100644
--- a/src/common/servlist.c
+++ b/src/common/servlist.c
@@ -814,6 +814,29 @@ servlist_server_find (ircnet *net, char *name, int *pos)
 	return NULL;
 }
 
+commandentry *
+servlist_command_find (ircnet *net, char *cmd, int *pos)
+{
+	GSList *list = net->commandlist;
+	commandentry *entry;
+	int i = 0;
+
+	while (list)
+	{
+		entry = list->data;
+		if (strcmp (entry->command, cmd) == 0)
+		{
+			if (pos)
+				*pos = i;
+			return entry;
+		}
+		i++;
+		list = list->next;
+	}
+
+	return NULL;
+}
+
 /* find a network (e.g. (ircnet *) to "FreeNode") from a hostname
    (e.g. "irc.eu.freenode.net") */
 
@@ -881,6 +904,20 @@ servlist_server_add (ircnet *net, char *name)
 	return serv;
 }
 
+commandentry *
+servlist_command_add (ircnet *net, char *cmd)
+{
+	commandentry *entry;
+
+	entry = malloc (sizeof (commandentry));
+	memset (entry, 0, sizeof (commandentry));
+	entry->command = strdup (cmd);
+
+	net->commandlist = g_slist_append (net->commandlist, entry);
+
+	return entry;
+}
+
 void
 servlist_server_remove (ircnet *net, ircserver *serv)
 {
@@ -901,6 +938,14 @@ servlist_server_remove_all (ircnet *net)
 	}
 }
 
+void
+servlist_command_remove (ircnet *net, commandentry *entry)
+{
+	free (entry->command);
+	free (entry);
+	net->commandlist = g_slist_remove (net->commandlist, entry);
+}
+
 static void
 free_and_clear (char *str)
 {
@@ -948,8 +993,8 @@ servlist_net_remove (ircnet *net)
 	free_and_clear (net->pass);
 	if (net->autojoin)
 		free (net->autojoin);
-	if (net->command)
-		free (net->command);
+	if (net->commandlist)
+		g_slist_free_full (net->commandlist, (GDestroyNotify) g_free);
 	if (net->comment)
 		free (net->comment);
 	if (net->encoding)
@@ -963,7 +1008,9 @@ servlist_net_remove (ircnet *net)
 	{
 		serv = list->data;
 		if (serv->network == net)
+		{
 			serv->network = NULL;
+		}
 		list = list->next;
 	}
 }
@@ -1037,7 +1084,6 @@ servlist_load (void)
 	FILE *fp;
 	char buf[2048];
 	int len;
-	char *tmp;
 	ircnet *net = NULL;
 
 	/* simple migration we will keep for a short while */
@@ -1084,9 +1130,9 @@ servlist_load (void)
 				net->autojoin = strdup (buf + 2);
 				break;
 			case 'C':
-				if (net->command)
+				/*if (net->command)
 				{
-					/* concat extra commands with a \n separator */
+					// concat extra commands with a \n separator
 					tmp = net->command;
 					net->command = malloc (strlen (tmp) + strlen (buf + 2) + 2);
 					strcpy (net->command, tmp);
@@ -1095,6 +1141,8 @@ servlist_load (void)
 					free (tmp);
 				} else
 					net->command = strdup (buf + 2);
+					*/
+				servlist_command_add (net, buf + 2);
 				break;
 			case 'F':
 				net->flags = atoi (buf + 2);
@@ -1161,13 +1209,6 @@ servlist_check_encoding (char *charset)
 	return FALSE;
 }
 
-static int
-servlist_write_ccmd (char *str, void *fp)
-{
-	return fprintf (fp, "C=%s\n", (str[0] == '/') ? str + 1 : str);
-}
-
-
 int
 servlist_save (void)
 {
@@ -1175,8 +1216,10 @@ servlist_save (void)
 	char *buf;
 	ircnet *net;
 	ircserver *serv;
+	commandentry *cmd;
 	GSList *list;
-	GSList *hlist;
+	GSList *netlist;
+	GSList *cmdlist;
 #ifndef WIN32
 	int first = FALSE;
 
@@ -1235,17 +1278,22 @@ servlist_save (void)
 			}
 		}
 
-		if (net->command)
-			token_foreach (net->command, '\n', servlist_write_ccmd, fp);
-
 		fprintf (fp, "F=%d\nD=%d\n", net->flags, net->selected);
 
-		hlist = net->servlist;
-		while (hlist)
+		netlist = net->servlist;
+		while (netlist)
 		{
-			serv = hlist->data;
+			serv = netlist->data;
 			fprintf (fp, "S=%s\n", serv->hostname);
-			hlist = hlist->next;
+			netlist = netlist->next;
+		}
+
+		cmdlist = net->commandlist;
+		while (cmdlist)
+		{
+			cmd = cmdlist->data;
+			fprintf (fp, "C=%s\n", cmd->command);
+			cmdlist = cmdlist->next;
 		}
 
 		if (fprintf (fp, "\n") < 1)
diff --git a/src/common/servlist.h b/src/common/servlist.h
index c38c5129..141df127 100644
--- a/src/common/servlist.h
+++ b/src/common/servlist.h
@@ -25,6 +25,11 @@ typedef struct ircserver
 	char *hostname;
 } ircserver;
 
+typedef struct commandentry
+{
+	char *command;
+} commandentry;
+
 typedef struct ircnet
 {
 	char *name;
@@ -34,11 +39,11 @@ typedef struct ircnet
 	char *real;
 	char *pass;
 	char *autojoin;
-	char *command;
 	int logintype;
 	char *comment;
 	char *encoding;
 	GSList *servlist;
+	GSList *commandlist;
 	int selected;
 	guint32 flags;
 } ircnet;
@@ -72,9 +77,12 @@ void servlist_net_remove (ircnet *net);
 ircnet *servlist_net_find (char *name, int *pos, int (*cmpfunc) (const char *, const char *));
 ircnet *servlist_net_find_from_server (char *server_name);
 
-void servlist_server_remove (ircnet *net, ircserver *serv);
-ircserver *servlist_server_add (ircnet *net, char *name);
 ircserver *servlist_server_find (ircnet *net, char *name, int *pos);
+commandentry *servlist_command_find (ircnet *net, char *cmd, int *pos);
+ircserver *servlist_server_add (ircnet *net, char *name);
+commandentry *servlist_command_add (ircnet *net, char *command);
+void servlist_server_remove (ircnet *net, ircserver *serv);
+void servlist_command_remove (ircnet *net, commandentry *entry);
 
 void joinlist_split (char *autojoin, GSList **channels, GSList **keys);
 gboolean joinlist_is_in_list (server *serv, char *channel);
diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c
index 2cd74da2..3c9ecd22 100644
--- a/src/fe-gtk/servlistgui.c
+++ b/src/fe-gtk/servlistgui.c
@@ -278,6 +278,36 @@ servlist_servers_populate (ircnet *net, GtkWidget *treeview)
 }
 
 static void
+servlist_commands_populate (ircnet *net, GtkWidget *treeview)
+{
+	GtkListStore *store;
+	GtkTreeIter iter;
+	int i;
+	commandentry *entry;
+	GSList *list = net->commandlist;
+
+	store = (GtkListStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+	gtk_list_store_clear (store);
+
+	i = 0;
+	while (list)
+	{
+		entry = list->data;
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter, 0, entry->command, 1, 1, -1);
+
+		if (net->selected == i)
+		{
+			/* select this server */
+			servlist_select_and_show (GTK_TREE_VIEW (treeview), &iter, store);
+		}
+
+		i++;
+		list = list->next;
+	}
+}
+
+static void
 servlist_networks_populate_ (GtkWidget *treeview, GSList *netlist, gboolean favorites)
 {
 	GtkListStore *store;
@@ -384,7 +414,7 @@ servlist_addserver (void)
 
 	/* select this server */
 	servlist_select_and_show (GTK_TREE_VIEW (edit_trees[SERVER_TREE]), &iter, store);
-	/*servlist_start_editing (GTK_TREE_VIEW (treeview));*/
+	servlist_start_editing (GTK_TREE_VIEW (edit_trees[SERVER_TREE]));
 
 	servlist_server_row_cb (gtk_tree_view_get_selection (GTK_TREE_VIEW (networks_tree)), NULL);
 }
@@ -399,31 +429,18 @@ servlist_addcommand (void)
 		return;
 
 	store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (edit_trees[CMD_TREE])));
+	servlist_command_add (selected_net, "ECHO hello");
 
 	gtk_list_store_append (store, &iter);
-	gtk_list_store_set (store, &iter, 0, "", 1, 1, -1);
+	gtk_list_store_set (store, &iter, 0, "ECHO hello", 1, 1, -1);
 
 	servlist_select_and_show (GTK_TREE_VIEW (edit_trees[CMD_TREE]), &iter, store);
+	servlist_start_editing (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
 
 	servlist_server_row_cb (gtk_tree_view_get_selection (GTK_TREE_VIEW (networks_tree)), NULL);
 }
 
 static void
-servlist_deletecommand (void)
-{
-	GtkTreeSelection *sel;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-
-	/* find the selected item in the GUI */
-	model = gtk_tree_view_get_model (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
-	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
-
-	if (gtk_tree_selection_get_selected (sel, &model, &iter))
-		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-}
-
-static void
 servlist_addnet_cb (GtkWidget *item, GtkTreeView *treeview)
 {
 	GtkTreeIter iter;
@@ -681,6 +698,7 @@ servlist_edit_cb (GtkWidget *but, gpointer none)
 	edit_win = servlist_open_edit (serverlist_win, selected_net);
 	gtkutil_set_icon (edit_win);
 	servlist_servers_populate (selected_net, edit_trees[SERVER_TREE]);
+	servlist_commands_populate (selected_net, edit_trees[CMD_TREE]);
 	g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (edit_trees[SERVER_TREE]))),
 							"changed", G_CALLBACK (servlist_server_row_cb), NULL);
 	g_signal_connect (G_OBJECT (edit_win), "delete_event",
@@ -762,7 +780,55 @@ servlist_deleteserver_cb (void)
 		serv = servlist_server_find (selected_net, servname, &pos);
 		g_free (servname);
 		if (serv)
+		{
 			servlist_deleteserver (serv, model);
+		}
+	}
+}
+
+static void
+servlist_deletecommand (commandentry *entry, GtkTreeModel *model)
+{
+	GtkTreeSelection *sel;
+	GtkTreeIter iter;
+
+	/* remove from GUI */
+	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
+	if (gtk_tree_selection_get_selected (sel, &model, &iter))
+	{
+		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+	}
+
+	/* remove from list */
+	if (selected_net)
+	{
+		servlist_command_remove (selected_net, entry);
+	}
+}
+
+static void
+servlist_deletecommand_cb (void)
+{
+	GtkTreeSelection *sel;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	char *command;
+	commandentry *entry;
+	int pos;
+
+	/* find the selected item in the GUI */
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
+	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (edit_trees[CMD_TREE]));
+
+	if (gtk_tree_selection_get_selected (sel, &model, &iter))
+	{
+		gtk_tree_model_get (model, &iter, 0, &command, -1);			/* query the content of the selection */
+		entry = servlist_command_find (selected_net, command, &pos);
+		g_free (command);
+		if (entry)
+		{
+			servlist_deletecommand (entry, model);
+		}
 	}
 }
 
@@ -874,21 +940,6 @@ servlist_editkey_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, GtkT
 }
 
 static void
-servlist_editcommand_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, GtkTreeModel *model)
-{
-	GtkTreeIter iter;
-
-	if (!servlist_get_iter_from_name (model, name, &iter))
-		return;
-
-	/* delete empty item */
-	if (newval[0] == 0)
-		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-	else
-		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, newval, -1);
-}
-
-static void
 servlist_addchannel (char *channel)
 {
 	GtkTreeIter iter;
@@ -905,7 +956,7 @@ servlist_addchannel (char *channel)
 }
 
 static void
-servlist_deletechannel (void)
+servlist_deletechannel_cb (void)
 {
 	GtkTreeSelection *sel;
 	GtkTreeModel *model;
@@ -947,10 +998,10 @@ servlist_deletebutton_cb (GtkWidget *item, GtkNotebook *notebook)
 						servlist_deleteserver_cb ();
 						break;
 				case CHANNEL_TREE:
-						servlist_deletechannel ();
+						servlist_deletechannel_cb ();
 						break;
 				case CMD_TREE:
-						servlist_deletecommand ();
+						servlist_deletecommand_cb ();
 						break;
 				default:
 						break;
@@ -1392,6 +1443,20 @@ servlist_sanitize_hostname (char *host)
 	return ret;
 }
 
+/* remove leading slash */
+static char *
+servlist_sanitize_command (char *cmd)
+{
+	if (cmd[0] == '/')
+	{
+		return (g_strdup (cmd + 1));
+	}
+	else
+	{
+		return (g_strdup (cmd));
+	}
+}
+
 static void
 servlist_editserver_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2,
 								gpointer user_data)
@@ -1437,6 +1502,49 @@ servlist_editserver_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2,
 }
 
 static void
+servlist_editcommand_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2, gpointer user_data)
+{
+	GtkTreeModel *model = (GtkTreeModel *)user_data;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	char *cmd;
+	commandentry *entry;
+
+	if (!selected_net)
+		return;
+
+	path = gtk_tree_path_new_from_string (arg1);
+
+	if (!gtk_tree_model_get_iter (model, &iter, path))
+	{
+		gtk_tree_path_free (path);
+		return;
+	}
+
+	gtk_tree_model_get (model, &iter, 0, &cmd, -1);
+	entry = servlist_command_find (selected_net, cmd, NULL);
+	g_free (cmd);
+
+	if (entry)
+	{
+		/* delete empty item */
+		if (arg2[0] == 0)
+		{
+			servlist_deletecommand (entry, model);
+			gtk_tree_path_free (path);
+			return;
+		}
+
+		cmd = entry->command;
+		entry->command = servlist_sanitize_command (arg2);
+		gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, entry->command, -1);
+		free (cmd);
+	}
+
+	gtk_tree_path_free (path);
+}
+
+static void
 servlist_combo_cb (GtkEntry *entry, gpointer userdata)
 {
 	if (!selected_net)
@@ -1596,7 +1704,8 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 	vbox5 = gtk_vbox_new (FALSE, 0);
 	gtk_container_add (GTK_CONTAINER (editwindow), vbox5);
 
-	/* tabs and buttons */
+
+	/* Tabs and buttons */
 	hbox1 = gtk_hbox_new (FALSE, 0);
 	gtk_box_pack_start (GTK_BOX (vbox5), hbox1, TRUE, TRUE, 4);
 
@@ -1611,18 +1720,14 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 	gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);
 	gtk_box_pack_start (GTK_BOX (hbox1), notebook, TRUE, TRUE, SERVLIST_X_PADDING);
 
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2),
-											  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2),
-													 GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4),
-											  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4),
-													 GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5),
-											  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5),
-													 GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_SHADOW_IN);
+
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow4), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow4),	GTK_SHADOW_IN);
+
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_SHADOW_IN);
 
 
 	/* Server Tree */
@@ -1681,6 +1786,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 	gtk_tree_sortable_set_sort_column_id ((GtkTreeSortable *)model, 0, GTK_SORT_ASCENDING);
 	servlist_channels_populate (selected_net, treeview_channels);
 
+
 	/* Command Tree */
 	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
 	model = GTK_TREE_MODEL (store);
@@ -1701,6 +1807,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 								"editable", 1,
 								NULL);
 
+
 	/* Button Box */
 	vbuttonbox1 = gtk_vbutton_box_new ();
 	gtk_box_set_spacing (GTK_BOX (vbuttonbox1), 3);
@@ -1725,7 +1832,8 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 	gtk_container_add (GTK_CONTAINER (vbuttonbox1), buttonedit);
 	GTK_WIDGET_SET_FLAGS (buttonedit, GTK_CAN_DEFAULT);
 
-	/* checkboxes and entries */
+
+	/* Checkboxes and entries */
 	table3 = gtk_table_new (13, 2, FALSE);
 	gtk_box_pack_start (GTK_BOX (vbox5), table3, FALSE, FALSE, 0);
 	gtk_table_set_row_spacings (GTK_TABLE (table3), 2);
@@ -1765,7 +1873,8 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
 	comboboxentry_charset = servlist_create_charsetcombo ();
 	gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 1, 2, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2);
 
-	/* rule and close button */
+
+	/* Rule and Close button */
 	hseparator2 = gtk_hseparator_new ();
 	gtk_box_pack_start (GTK_BOX (vbox5), hseparator2, FALSE, FALSE, 8);