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 @@ -277,6 +277,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) { @@ -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,30 +429,17 @@ 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) { @@ -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); + } } } @@ -873,21 +939,6 @@ servlist_editkey_cb (GtkCellRendererText *cell, gchar *name, gchar *newval, GtkT gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, newval, -1); } -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) { @@ -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) @@ -1436,6 +1501,49 @@ servlist_editserver_cb (GtkCellRendererText *cell, gchar *arg1, gchar *arg2, gtk_tree_path_free (path); } +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) { @@ -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);