Двоичные файлы vqcc-gtk-0.5/po/ru.gmo и vqcc-gtk-0.5.1-shaman5/po/ru.gmo различаются
diff -NrU2 vqcc-gtk-0.5/po/ru.po vqcc-gtk-0.5.1-shaman5/po/ru.po
--- vqcc-gtk-0.5/po/ru.po	2005-01-10 00:30:22.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/po/ru.po	2005-04-13 19:03:17.000000000 +0400
@@ -152,4 +152,9 @@
 msgstr "<b>Отправить сообщение</b>"
 
+#: src/gui_ulist.c:163
+msgid "<b>Send mass message</b>"
+msgstr "<b>Отправить массовое сообщение</b>"
+
+
 #. "Beep"
 #: src/gui_ulist.c:168
@@ -470,13 +475,20 @@
 msgstr "Сообщение от %s: %s"
 
-#: src/gui_msg.c:671
-#, fuzzy
+#: src/gui_msg.c:828
 msgid "Show messages in windows"
 msgstr "Показывать принятые сообщения в окнах"
 
-#: src/gui_msg.c:673
+#: src/gui_msg.c:830
 msgid "Maximum message windows"
 msgstr "Максимум окон сообщений"
 
+#: src/gui_msg.c:832
+msgid "Minimize received private messages"
+msgstr "Сворачивать полученные личные сообщения"
+
+#: src/gui_msg.c:834
+msgid "Minimize received mass messages"
+msgstr "Сворачивать полученные массовые сообщения"
+
 #: src/gui_msg.c:675
 msgid "CTRL-Enter sends message"
@@ -487,7 +499,7 @@
 msgstr "Размер окна отправки сообщения"
 
-#: src/gui_msg.c:679
+#: src/gui_msg.c:840
 msgid "Receive message when in Offline or DND mode"
-msgstr ""
+msgstr "Получать сообщения когда в режиме Offline или DND"
 
 #: src/idle.c:194
@@ -833,4 +845,12 @@
 msgstr "Сетевая кодировка"
 
+#: src/net.c:940
+msgid "Secondary network charset encoding"
+msgstr "Вторичная сетевая кодировка"
+
+#: src/net.c:942
+msgid "Send messages in primary charset"
+msgstr "Отправлять сообщения в основной кодировке"
+
 #: src/net.c:936
 msgid "Reply to user information requests"
diff -NrU2 vqcc-gtk-0.5/src/gui.c vqcc-gtk-0.5.1-shaman5/src/gui.c
--- vqcc-gtk-0.5/src/gui.c	2005-01-07 18:11:01.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/gui.c	2005-04-13 19:07:05.000000000 +0400
@@ -387,4 +387,5 @@
 		if(nickname_valid(new_nick)) {
 			raise_event(EVENT_IFACE_NICKNAME_ENTERED, (gpointer)new_nick, 0);
+			raise_event(EVENT_IFACE_STORE_CONFIG, NULL, 0);
 		}
 
@@ -437,5 +438,6 @@
 	GtkWidget * vbox, * w, * b, * hpaned;
 	struct iface_main_wnd * mw;
-
+	
+	
 	mw = g_new(struct iface_main_wnd, 1);
 	mw->topic_modified = FALSE;
@@ -524,5 +526,11 @@
 	gtk_container_set_border_width(GTK_CONTAINER(b), 3);
 	gtk_container_add(GTK_CONTAINER(mw->userlist_frame_w), b);
-	mw->userlist = gui_ulist_create();
+	
+	/*this shuld be corrected shaman*/
+	main_ulist_model=gui_ulist_create_model(FALSE);
+	mw->userlist=gui_ulist_create(main_ulist_model,FALSE);
+	
+	
+	
 	gtk_box_pack_start(GTK_BOX(b), mw->userlist, TRUE, TRUE, 0);
 
@@ -541,5 +549,5 @@
 	gtk_widget_destroy(mw->widget);
 
-	gui_ulist_free();
+	gui_ulist_free(&main_ulist_model);
 
 	g_free(mw);
@@ -970,3 +978,2 @@
 	return main_wnd->widget;
 }
-
diff -NrU2 vqcc-gtk-0.5/src/gui_config.c vqcc-gtk-0.5.1-shaman5/src/gui_config.c
--- vqcc-gtk-0.5/src/gui_config.c	2005-01-06 13:16:08.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/gui_config.c	2005-04-13 18:50:34.000000000 +0400
@@ -1,1107 +1,1179 @@
-/*
- * gui_config.c: implements configuration dialog
- * Copyright (C) 2002-2004 Saulius Menkevicius
- *
- * 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
- *
- * $Id: gui_config.c,v 1.43 2005/01/06 10:16:08 bobas Exp $
- */
-
-#include <stdio.h>
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdkkeysyms.h>
-
-#include "main.h"
-#include "gui.h"
-#include "prefs.h"
-#include "net.h"
-#include "idle.h"
-#include "gui_config.h"
-#include "gui_misc.h"
-#include "gui_msg.h"
-#include "gui_tray.h"
-#include "gui_page.h"
-#include "util.h"
-
-#define HAVE_ENCODING_COMBO_WIDGET \
-	((GTK_MAJOR_VERSION > 2) || ((GTK_MAJOR_VERSION==2) && (GTK_MINOR_VERSION>=4)))
-
-/** geometries
-  ************************************/
-#define GEOM_DLG_PAGE_BORDER	6
-
-/** structure definitions
-  ************************************/
-struct config_dlg {
-	gboolean is_changed, gathering;
-
-	GtkTreeStore * prefs_tree_store;
-	GtkWidget * dlg_w, * prefs_tree_w, * notebook_w,
-
-		/* Network widgets */
-		* net_type_w,
-		* net_port_w,
-		* net_broadcast_label_w, * net_broadcast_w,
-		* net_use_multicast_w,
-		* net_multicast_label_w, * net_multicast_w,
-
-		* net_reply_w,
-		* net_log_w,
-		* net_channel_greet_w,
-		* net_charset_w,
-#if(HAVE_ENCODING_COMBO_WIDGET)
-		* net_charset_combo_w,
-#endif
-
-		/* User list */
-		* userlist_refresh_w,
-		* userlist_keep_unreplied_users_w,
-
-		/* Idle frame widgets */
-		* idle_enable_w,
-		* auto_away_w,
-		* auto_offline_w,
-
-		/* Pages */
-		* pages_show_topic_entry,
-		* pages_present_on_private,
-		* pages_log_current_w,
-		* date_channel_w,
-		* date_private_w,
-		* date_status_w,
-		* pages_notebook_pos_w,
-		* pages_suppress_join_leave_w,
-		* pages_suppress_rename_w,
-		* pages_suppress_mode_change_w,
-
-		/* Messages */
-		* msg_max_w,
-		* msg_max_label_w,
-		* msg_show_window_w,
-		* msg_ignore_mass_w,
-		* msg_ctrl_return_w,
-		* msg_show_messages_in_offline_dnd_w,
-
-		/* Tray icon */
-		* tray_enable_w,
-		* tray_hide_on_startup_w,
-		* tray_trigger_joinleave_w,
-		* tray_trigger_channel_w,
-		* tray_trigger_private_w,
-		* tray_trigger_status_w,
-		* tray_trigger_topic_w,
-		* tray_tooltip_lines_w,
-		* tray_tooltip_lines_label_w,
-
-		/* Misc */
-		* save_on_exit_w,
-		* keep_window_size_w,
-		* motd_w,
-		* motd_away_w,
-
-		/* action_area buttons */
-		* save_w,
-		* apply_w;
-};
-#define PCONFIG_DLG(p) ((struct config_dlg*)p)
-
-enum config_tree_model_enum {
-	CONFIG_TREE_NAME,
-	CONFIG_TREE_INDEX,
-	CONFIG_TREE_NUM
-};
-
-/** static variables
- */
-static struct config_dlg * the_dlg; 
-
-#if(HAVE_ENCODING_COMBO_WIDGET)
-const gchar *
-supported_encodings[] = {
-	"KOI8-R", "CP1251",	/* cyrillic */
-	"ISO-8859-2",		/* central europe */
-	"ISO-8859-13",		/* baltic */
-	"ISO-8859-7",		/* greek */
-	"ISO-8859-8",		/* hebrew */
-	"ISO-8859-9",		/* turkish */
-	"ISO-8859-15",		/* western europe */
-	"ISO-2022-JP", "SJIS",	/* japanese */
-	"CP1256",		/* arabic */
-	"GB18030",		/* chinese */
-	"UTF-8",
-	NULL
-};
-#endif
-
-/** static rountines
- */
-static void set_config_dlg_modified(struct config_dlg *, gboolean);
-static void sync_dlg_from_config(struct config_dlg *);
-static void set_config_from_dlg(struct config_dlg *);
-static void destroy_config_dlg(struct config_dlg **);
-
-static void
-set_ipv4_entry(GtkWidget * entry_w, guint32 addr)
-{
-	char * str = util_inet_ntoa(addr);
-	gtk_entry_set_text(GTK_ENTRY(entry_w), str);
-	g_free(str);
+/*
+ * gui_config.c: implements configuration dialog
+ * Copyright (C) 2002-2004 Saulius Menkevicius
+ *
+ * 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
+ *
+ * $Id: gui_config.c,v 1.43 2005/01/06 10:16:08 bobas Exp $
+ */
+
+#include <stdio.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "main.h"
+#include "gui.h"
+#include "prefs.h"
+#include "net.h"
+#include "idle.h"
+#include "gui_config.h"
+#include "gui_misc.h"
+#include "gui_msg.h"
+#include "gui_tray.h"
+#include "gui_page.h"
+#include "util.h"
+
+#define HAVE_ENCODING_COMBO_WIDGET \
+	((GTK_MAJOR_VERSION > 2) || ((GTK_MAJOR_VERSION==2) && (GTK_MINOR_VERSION>=4)))
+
+/** geometries
+  ************************************/
+#define GEOM_DLG_PAGE_BORDER	6
+
+/** structure definitions
+  ************************************/
+struct config_dlg {
+	gboolean is_changed, gathering;
+
+	GtkTreeStore * prefs_tree_store;
+	GtkWidget * dlg_w, * prefs_tree_w, * notebook_w,
+
+		/* Network widgets */
+		* net_type_w,
+		* net_port_w,
+		* net_broadcast_label_w, * net_broadcast_w,
+		* net_use_multicast_w,
+		* net_multicast_label_w, * net_multicast_w,
+
+		* net_reply_w,
+		* net_log_w,
+		* net_channel_greet_w,
+		* net_charset_w,
+		* net_charset2_w,
+		* net_charset_choice_w,
+#if(HAVE_ENCODING_COMBO_WIDGET)
+		* net_charset_combo_w,
+	    * net_secondary_charset_combo_w,
+#endif
+		
+		/* User list */
+		* userlist_refresh_w,
+		* userlist_keep_unreplied_users_w,
+
+		/* Idle frame widgets */
+		* idle_enable_w,
+		* auto_away_w,
+		* auto_offline_w,
+
+		/* Pages */
+		* pages_show_topic_entry,
+		* pages_present_on_private,
+		* pages_log_current_w,
+		* date_channel_w,
+		* date_private_w,
+		* date_status_w,
+		* pages_notebook_pos_w,
+		* pages_suppress_join_leave_w,
+		* pages_suppress_rename_w,
+		* pages_suppress_mode_change_w,
+
+		/* Messages */
+		* msg_max_w,
+		* msg_max_label_w,
+		* msg_show_window_w,
+		* msg_minimize_mass_messages_w,
+		* msg_minimize_private_messages_w,
+		* msg_ignore_mass_w,
+		* msg_ctrl_return_w,
+		* msg_show_messages_in_offline_dnd_w,
+
+		/* Tray icon */
+		* tray_enable_w,
+		* tray_hide_on_startup_w,
+		* tray_trigger_joinleave_w,
+		* tray_trigger_channel_w,
+		* tray_trigger_private_w,
+		* tray_trigger_status_w,
+		* tray_trigger_topic_w,
+		* tray_tooltip_lines_w,
+		* tray_tooltip_lines_label_w,
+
+		/* Misc */
+		* save_on_exit_w,
+		* keep_window_size_w,
+		* motd_w,
+		* motd_away_w,
+
+		/* action_area buttons */
+		* save_w,
+		* apply_w;
+};
+#define PCONFIG_DLG(p) ((struct config_dlg*)p)
+
+enum config_tree_model_enum {
+	CONFIG_TREE_NAME,
+	CONFIG_TREE_INDEX,
+	CONFIG_TREE_NUM
+};
+
+/** static variables
+ */
+static struct config_dlg * the_dlg; 
+
+#if(HAVE_ENCODING_COMBO_WIDGET)
+const gchar *
+supported_encodings[] = {
+	"KOI8-R", "CP1251",	/* cyrillic */
+	"ISO-8859-2",		/* central europe */
+	"ISO-8859-13",		/* baltic */
+	"ISO-8859-7",		/* greek */
+	"ISO-8859-8",		/* hebrew */
+	"ISO-8859-9",		/* turkish */
+	"ISO-8859-15",		/* western europe */
+	"ISO-2022-JP", "SJIS",	/* japanese */
+	"CP1256",		/* arabic */
+	"GB18030",		/* chinese */
+	"UTF-8",
+	NULL
+};
+#endif
+
+/** static rountines
+ */
+static void set_config_dlg_modified(struct config_dlg *, gboolean);
+static void sync_dlg_from_config(struct config_dlg *);
+static void set_config_from_dlg(struct config_dlg *);
+static void destroy_config_dlg(struct config_dlg **);
+
+static void
+set_ipv4_entry(GtkWidget * entry_w, guint32 addr)
+{
+	char * str = util_inet_ntoa(addr);
+	gtk_entry_set_text(GTK_ENTRY(entry_w), str);
+	g_free(str);
+}
+
+static void
+prefs_dlg_check_button_toggled_cb(GtkToggleButton * togglebutton_w, gpointer dlg)
+{
+	/* update dialog state */
+	set_config_dlg_modified(PCONFIG_DLG(dlg), TRUE);
+}
+
+static GtkWidget *
+add_check_button(
+	struct config_dlg * dlg,
+	GtkWidget * b, const gchar * prefs_name,
+	GCallback toggled_cb, gpointer toggled_cb_user_data)
+{
+	GtkWidget * w;
+
+	w = gtk_check_button_new_with_mnemonic(prefs_description(prefs_name));
+	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 0);
+
+	g_signal_connect(
+		G_OBJECT(w), "toggled",
+		G_CALLBACK(prefs_dlg_check_button_toggled_cb), (gpointer)dlg);
+
+	if(toggled_cb)
+		g_signal_connect(G_OBJECT(w), "toggled", toggled_cb, toggled_cb_user_data);
+
+	return w;
+}
+
+static void
+prefs_dlg_spin_button_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
+{
+	/* update dialog state */
+	set_config_dlg_modified(PCONFIG_DLG(dlg), TRUE);
+}
+
+static GtkWidget *
+add_spin_button(
+	struct config_dlg * dlg,
+	GtkWidget * b,
+	const gchar * prefs_name,
+	int min, int max,
+	GtkWidget ** p_label_w,
+	GCallback value_changed_cb,
+	gpointer value_changed_cb_data)
+{
+	GtkWidget * w, * hb, * label_w;
+
+	g_assert(dlg && b && min<max);
+
+	hb = gtk_hbox_new(FALSE, 2);
+	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
+
+	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
+	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
+	if(p_label_w)
+		*p_label_w = label_w;
+
+	w = gtk_spin_button_new_with_range(min, max, 1);
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), w);
+	gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0);
+
+	g_signal_connect(
+		G_OBJECT(w), "value-changed",
+		G_CALLBACK(prefs_dlg_spin_button_changed_cb), (gpointer)dlg);
+
+	if(value_changed_cb)
+		g_signal_connect(
+			G_OBJECT(w), "value-changed",
+			G_CALLBACK(value_changed_cb), value_changed_cb_data);
+
+	return w;
+}
+
+static void
+prefs_dlg_option_changed_cb(GtkOptionMenu * o, struct config_dlg * dlg)
+{
+	set_config_dlg_modified(dlg, TRUE);
+}
+
+static GtkWidget *
+add_option(
+	struct config_dlg * dlg,
+	GtkWidget * b,
+	const gchar * prefs_name,
+	GList * entries,
+	GtkWidget ** p_label_w)
+{
+	GtkWidget * o, * hb, * menu_w, * label_w;
+
+	g_assert(b && entries);
+
+	hb = gtk_hbox_new(FALSE, 2);
+	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
+
+	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
+	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
+	if(p_label_w) *p_label_w = label_w;
+
+	/* make option menu */
+	o = gtk_option_menu_new();
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), o);
+	menu_w = gtk_menu_new();
+	for(; entries; entries = entries->next) {
+		gtk_menu_shell_append(
+			GTK_MENU_SHELL(menu_w),
+			gtk_menu_item_new_with_mnemonic((gchar*)entries->data));
+	}
+	gtk_option_menu_set_menu(GTK_OPTION_MENU(o), menu_w);
+	gtk_box_pack_start(GTK_BOX(hb), o, FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(o), "changed", G_CALLBACK(prefs_dlg_option_changed_cb), dlg);
+
+	return o;
+}
+
+static void
+prefs_dlg_entry_changed_cb(GtkEntry * w, struct config_dlg * dlg)
+{
+	set_config_dlg_modified(dlg, TRUE);
+}
+
+static GtkWidget *
+add_entry(
+	struct config_dlg * dlg,
+	GtkWidget * b,
+	const gchar * prefs_name,
+	GtkWidget ** p_label_w)
+{
+	GtkWidget * hb, * w, * label_w;
+
+	hb = gtk_hbox_new(FALSE, 2);
+	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
+
+	/* make label */
+	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
+	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
+	if(p_label_w) *p_label_w = label_w;
+
+	/* make edit entry */
+	w = gtk_entry_new();
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), w);
+	gtk_box_pack_start(GTK_BOX(hb), w, TRUE, TRUE, 0);
+	g_signal_connect(
+		G_OBJECT(w), "changed",
+		G_CALLBACK(prefs_dlg_entry_changed_cb), (gpointer)dlg);
+
+	return w;
+}
+
+static GtkWidget *
+add_widget(
+	struct config_dlg * dlg,
+	GtkWidget * frame_vbox,
+	const gchar * label_text, GtkWidget * widget)
+{
+	GtkWidget * hbox = gtk_hbox_new(FALSE, 2);
+
+	if(label_text) {
+		gtk_box_pack_start(
+			GTK_BOX(hbox), gtk_label_new_with_mnemonic(label_text),
+			FALSE, FALSE, 0);
+	}
+	gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(frame_vbox), hbox, FALSE, FALSE, 0);
+
+	return widget;
+}
+
+/* gtk 2.4+ has support for encoding combo widget
+ */
+#if(HAVE_ENCODING_COMBO_WIDGET)
+
+static GtkWidget *
+net_frame_encoding_combo(
+	struct config_dlg * dlg,
+	const gchar * label_text)
+{
+	GtkWidget * combo_w;
+	const gchar ** encoding;
+	gboolean have_current_encoding;
+
+	combo_w = gtk_combo_box_entry_new_text();
+
+	/* add encodings to the combo box list */
+	have_current_encoding = FALSE;
+	for(encoding = supported_encodings; *encoding; encoding++) {
+		/* check encoding is supported on this system/glib */
+		gchar *enc_test = g_convert("a", 1, "UTF-8", *encoding, NULL,NULL,NULL);
+		if(!enc_test)
+			continue;
+		g_free(enc_test);
+
+		gtk_combo_box_append_text(GTK_COMBO_BOX(combo_w), *encoding);
+
+		/* check if this is the current encoding */
+		if(!g_utf8_collate(*encoding, prefs_str(PREFS_NET_ENCODING)))
+			have_current_encoding = TRUE;
+	}
+	if(!have_current_encoding) {
+		/* add the default encoding as it was not found in the list */
+		gtk_combo_box_prepend_text(GTK_COMBO_BOX(combo_w), prefs_str(PREFS_NET_ENCODING));
+	}
+
+	return combo_w;
+}
+
+
+/*Shaman changed*/
+static GtkWidget *
+net_frame_encoding_combo2(
+	struct config_dlg * dlg,
+	const gchar * label_text)
+{
+	GtkWidget * combo_w;
+	const gchar ** encoding;
+	gboolean have_current_encoding;
+
+	combo_w = gtk_combo_box_entry_new_text();
+
+	/* add encodings to the combo box list */
+	have_current_encoding = FALSE;
+	for(encoding = supported_encodings; *encoding; encoding++) {
+		/* check encoding is supported on this system/glib */
+		gchar *enc_test = g_convert("a", 1, "UTF-8", *encoding, NULL,NULL,NULL);
+		if(!enc_test)
+			continue;
+		g_free(enc_test);
+
+		gtk_combo_box_append_text(GTK_COMBO_BOX(combo_w), *encoding);
+
+		/* check if this is the current encoding */
+		if(!g_utf8_collate(*encoding, prefs_str(PREFS_NET_ENCODING)))
+			have_current_encoding = TRUE;
+	}
+	if(!have_current_encoding) {
+		/* add the default encoding as it was not found in the list */
+		gtk_combo_box_prepend_text(GTK_COMBO_BOX(combo_w), prefs_str(PREFS_NET_ENCODING));
+	}
+
+	return combo_w;
+}
+
+/*Shaman changed*/
+
+#endif
+
+static void
+net_detect_btn_clicked(GtkButton * button_w, struct config_dlg * dlg)
+{
+	raise_event(EVENT_IFACE_SHOW_NETDETECT_DLG, NULL, 0);
+}
+
+static void
+net_prefs_type_changed_cb(gint mode, gpointer userdata)
+{
+	struct config_dlg * dlg = (struct config_dlg *)userdata;
+
+	set_config_dlg_modified(dlg, TRUE);
+
+	if(mode==NET_TYPE_QCHAT) {
+		/* there's no option for multicast in quickchat mode */
+		gtk_widget_set_sensitive(dlg->net_use_multicast_w, FALSE);
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dlg->net_use_multicast_w), FALSE);
+	} else {
+		gtk_widget_set_sensitive(dlg->net_use_multicast_w, TRUE);
+	}
+}
+
+static void
+net_prefs_use_multicast_changed_cb(GtkToggleButton * button_w, struct config_dlg * dlg)
+{
+	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
+	
+	gtk_widget_set_sensitive(dlg->net_broadcast_label_w, !set);
+	gtk_widget_set_sensitive(dlg->net_broadcast_w, !set);
+
+	gtk_widget_set_sensitive(dlg->net_multicast_label_w, set);
+	gtk_widget_set_sensitive(dlg->net_multicast_w, set);
+}
+
+static GtkWidget *
+make_net_frame(struct config_dlg * dlg)
+{
+	GtkWidget * b, * detect_btn;
+
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	/* network type option menu */
+	dlg->net_type_w = add_widget(
+		dlg, b, prefs_description(PREFS_NET_TYPE),
+		util_net_type_option(net_prefs_type_changed_cb, (gpointer)dlg));
+
+	/* network port numer */
+	dlg->net_port_w = add_spin_button(dlg, b, PREFS_NET_PORT, 0, 65535, NULL, NULL, NULL);
+
+	/* brodcast & multicast addresses */
+	dlg->net_use_multicast_w = add_check_button(
+		dlg, b, PREFS_NET_USE_MULTICAST,
+		G_CALLBACK(net_prefs_use_multicast_changed_cb), (gpointer)dlg);
+	dlg->net_broadcast_w = add_entry(dlg, b, PREFS_NET_BROADCAST_MASK, &dlg->net_broadcast_label_w);
+	dlg->net_multicast_w = add_entry(dlg, b, PREFS_NET_MULTICAST_ADDR, &dlg->net_multicast_label_w);
+	net_prefs_use_multicast_changed_cb(GTK_TOGGLE_BUTTON(dlg->net_use_multicast_w), dlg);
+	net_prefs_type_changed_cb(
+		gtk_option_menu_get_history(GTK_OPTION_MENU(dlg->net_type_w)), dlg);
+
+	/* net charset selection widget */
+#if(HAVE_ENCODING_COMBO_WIDGET)
+	dlg->net_charset_combo_w = add_widget(
+		dlg, b, prefs_description(PREFS_NET_ENCODING),
+		net_frame_encoding_combo(dlg, prefs_description(PREFS_NET_ENCODING)));
+
+	dlg->net_charset_w = GTK_BIN(dlg->net_charset_combo_w)->child;
+	g_signal_connect(G_OBJECT(dlg->net_charset_w),
+		"changed", G_CALLBACK(prefs_dlg_entry_changed_cb), (gpointer) dlg);
+
+	/*Shaman changes*/
+	dlg->net_secondary_charset_combo_w = add_widget(
+		dlg, b, prefs_description(PREFS_NET_SECONDARY_ENCODING),
+		net_frame_encoding_combo2(dlg, prefs_description(PREFS_NET_SECONDARY_ENCODING)));
+
+	dlg->net_charset2_w = GTK_BIN(dlg->net_secondary_charset_combo_w)->child;
+	g_signal_connect(G_OBJECT(dlg->net_charset2_w),
+		"changed", G_CALLBACK(prefs_dlg_entry_changed_cb), (gpointer) dlg);
+
+	/*Shaman changes end*/
+#else
+	dlg->net_charset_w = add_entry(dlg, b, PREFS_NET_ENCODING, NULL);
+	dlg->net_charset2_w = add_entry(dlg, b, PREFS_NET_SECONDARY_ENCODING, NULL);
+#endif
+	/*choice primary/secondary charset for sending messages*/
+	dlg->net_charset_choice_w = add_check_button(dlg, b, PREFS_NET_CHARSET_CHOICE, NULL, NULL);
+	/* automatic detection button */
+	detect_btn = gtk_button_new_with_mnemonic(_("Detect available networks.."));
+	g_signal_connect(G_OBJECT(detect_btn), "clicked",
+		G_CALLBACK(net_detect_btn_clicked), (gpointer)dlg);
+	add_widget(dlg, b, NULL, detect_btn);
+
+	/* separator for miscelanious settings */
+	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 8);
+
+	/* whether to notify buddy/channel of our joins/leaves */
+	dlg->net_channel_greet_w = add_check_button(dlg, b, PREFS_NET_CHANNEL_NOTIFY, NULL, NULL);
+
+	/* whether to reply to info requests */
+	dlg->net_reply_w = add_check_button(dlg, b, PREFS_NET_REPLY_INFO_REQ, NULL, NULL);
+
+	/* whether to log network events verbosely */
+	dlg->net_log_w = add_check_button(dlg, b, PREFS_NET_VERBOSE, NULL, NULL);
+
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static GtkWidget *
+make_user_list_frame(struct config_dlg * dlg)
+{
+	GtkWidget * b;
+
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	/* update interval selection */
+	dlg->userlist_refresh_w
+		= add_spin_button(dlg, b, PREFS_USER_LIST_REFRESH, 1, 1000, NULL, NULL, NULL);
+
+	/* whether to remove dead users from the list */
+	dlg->userlist_keep_unreplied_users_w
+		= add_check_button(dlg, b, PREFS_USER_KEEP_UNREPLIED, NULL, NULL);
+
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static void
+idle_prefs_idle_auto_away_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
+{
+	gint away, offl;
+
+	offl = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w));
+	away = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w));
+
+	/* make sure away timeout is not larger than that of offline */
+	if(away > offl)
+		gtk_spin_button_set_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w), away);
+}
+
+static void
+idle_prefs_idle_auto_offline_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
+{
+	gint away, offl;
+
+	offl = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w));
+	away = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w));
+
+	/* make sure offline timeout is larger away's */
+	if(offl < away)
+		gtk_spin_button_set_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w), offl);
+}
+
+static void
+idle_prefs_idle_enabled_changed_cb(GtkToggleButton * togglebutton_w, gpointer dlg)
+{
+	gboolean set = gtk_toggle_button_get_active(togglebutton_w);
+
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->auto_away_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->auto_offline_w, set);
+}
+
+static GtkWidget *
+make_idle_frame(struct config_dlg * dlg)
+{
+	GtkWidget * box;
+
+	box = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(box), GEOM_DLG_PAGE_BORDER);
+
+	/* insert enabler/disabler */
+	dlg->idle_enable_w = add_check_button(
+		dlg, box, PREFS_IDLE_ENABLE,
+		G_CALLBACK(idle_prefs_idle_enabled_changed_cb), (gpointer)dlg);
+
+	/* insert auto-away & auto-offline */
+	dlg->auto_away_w = add_spin_button(
+		dlg, box, PREFS_IDLE_AUTO_AWAY, 1, 240, NULL,
+		G_CALLBACK(idle_prefs_idle_auto_away_changed_cb), (gpointer)dlg);
+	dlg->auto_offline_w = add_spin_button(
+		dlg, box, PREFS_IDLE_AUTO_OFFLINE, 1, 240, NULL,
+		G_CALLBACK(idle_prefs_idle_auto_offline_changed_cb), (gpointer)dlg);
+
+	gtk_widget_show_all(box);
+	return box;
+}
+
+static void
+messages_pref_in_window_toggled_cb(GtkToggleButton * button_w, gpointer dlg)
+{
+	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
+
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->msg_max_label_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->msg_max_w, set);
+}
+
+static GtkWidget *
+make_messages_frame(struct config_dlg * dlg)
+{
+	GtkWidget * b;
+
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	dlg->msg_ignore_mass_w = add_check_button(dlg, b, PREFS_NET_IGNORE_MASS_MSG, NULL, NULL);
+	dlg->msg_ctrl_return_w = add_check_button(dlg, b, PREFS_GUI_MSG_CTRL_ENTER, NULL, NULL);
+	dlg->msg_show_messages_in_offline_dnd_w =
+		add_check_button(dlg, b, PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND, NULL, NULL);
+	dlg->msg_minimize_private_messages_w = add_check_button(
+		dlg, b, PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES,
+		G_CALLBACK(messages_pref_in_window_toggled_cb), (gpointer)dlg);
+
+	dlg->msg_minimize_mass_messages_w = add_check_button(
+		dlg, b, PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES,
+		G_CALLBACK(messages_pref_in_window_toggled_cb), (gpointer)dlg);
+
+	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
+
+	dlg->msg_show_window_w = add_check_button(
+		dlg, b, PREFS_GUI_MSG_IN_WINDOW,
+		G_CALLBACK(messages_pref_in_window_toggled_cb), (gpointer)dlg);
+
+	dlg->msg_max_w = add_spin_button(
+		dlg, b, PREFS_GUI_MSG_MAX_WINDOWS,
+		1, 64, &dlg->msg_max_label_w, NULL, NULL);
+
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static GtkWidget *
+make_pages_frame(struct config_dlg * dlg)
+{
+	GList * pos_list;
+	GtkWidget * b;
+
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	dlg->pages_show_topic_entry = add_check_button(dlg, b, PREFS_GUI_TOPIC_BAR, NULL, NULL);
+
+	/* whether to present (show on top) main window when someone
+	 * opens private chat with us */
+	dlg->pages_present_on_private = add_check_button(
+		dlg, b, PREFS_GUI_PRESENT_ON_PRIVATE, NULL, NULL);
+
+	/* whether to duplicate new "Status" tab messages
+	 * in active sessions */
+	dlg->pages_log_current_w = add_check_button(dlg, b, PREFS_MAIN_LOG_GLOBAL, NULL, NULL);
+
+	/* add page notebook tab position option
+	 * (the order should be the same as in `enum GtkPositionType')
+	 */
+	pos_list = g_list_append(NULL, _("Left"));
+	pos_list = g_list_append(pos_list, _("Right"));
+	pos_list = g_list_append(pos_list, _("Top"));
+	pos_list = g_list_append(pos_list, _("Bottom"));
+	dlg->pages_notebook_pos_w = add_option(dlg, b, PREFS_GUI_PAGE_TAB_POS, pos_list, NULL);
+	g_list_free(pos_list);
+
+	/* message suppress settings */
+	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
+	dlg->pages_suppress_join_leave_w = add_check_button(
+		dlg, b, PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT, NULL, NULL);
+	dlg->pages_suppress_rename_w = add_check_button(
+		dlg, b, PREFS_SESS_SUPPRESS_RENAME_TEXT, NULL, NULL);
+	dlg->pages_suppress_mode_change_w = add_check_button(
+		dlg, b, PREFS_SESS_SUPPRESS_MODE_TEXT, NULL, NULL);
+
+	/* time stamp settings */
+	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
+
+	dlg->date_channel_w = add_check_button(dlg, b, PREFS_SESS_STAMP_CHANNEL, NULL, NULL);
+	dlg->date_private_w = add_check_button(dlg, b, PREFS_SESS_STAMP_PRIVATE, NULL, NULL);
+	dlg->date_status_w = add_check_button(dlg, b, PREFS_SESS_STAMP_STATUS, NULL, NULL);
+
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static void
+systray_pref_gui_tray_enable_toggled_cb(GtkToggleButton * button_w, gpointer dlg)
+{
+	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
+
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_hide_on_startup_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_joinleave_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_topic_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_status_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_private_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_channel_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_tooltip_lines_w, set);
+	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_tooltip_lines_label_w, set);
+}
+
+static GtkWidget *
+make_systray_frame(struct config_dlg * dlg)
+{
+	GtkWidget * b, * w;
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	dlg->tray_enable_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_ENABLE,
+		G_CALLBACK(systray_pref_gui_tray_enable_toggled_cb), (gpointer)dlg);
+
+	dlg->tray_hide_on_startup_w
+		= add_check_button(dlg, b, PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP, NULL, NULL);
+
+	w = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 8);
+
+	dlg->tray_trigger_joinleave_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE, NULL, NULL);
+	dlg->tray_trigger_channel_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_TRIGGERS_CHANNEL, NULL, NULL);
+	dlg->tray_trigger_private_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_TRIGGERS_PRIVATE, NULL, NULL);
+	dlg->tray_trigger_status_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_TRIGGERS_STATUS, NULL, NULL);
+	dlg->tray_trigger_topic_w = add_check_button(
+		dlg, b, PREFS_GUI_TRAY_TRIGGERS_TOPIC, NULL, NULL);
+
+	w = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 8);
+
+	dlg->tray_tooltip_lines_w = add_spin_button(
+		dlg, b, PREFS_GUI_TRAY_TOOLTIP_LINE_NUM,
+		0, 32, & dlg->tray_tooltip_lines_label_w, NULL, NULL);
+		
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static GtkWidget *
+make_settings_frame(struct config_dlg * dlg)
+{
+	GtkWidget * b, * w;
+
+	b = gtk_vbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
+
+	/* add other settings
+	 */
+	dlg->keep_window_size_w = add_check_button(dlg, b, PREFS_GUI_KEEP_SIZE, NULL, NULL);
+	dlg->save_on_exit_w = add_check_button(dlg, b, PREFS_PREFS_AUTO_SAVE, NULL, NULL);
+
+	w = gtk_hseparator_new();
+	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 0);
+
+	dlg->motd_w = add_entry(dlg, b, PREFS_NET_MOTD, NULL);
+	dlg->motd_away_w = add_entry(dlg, b, PREFS_NET_MOTD_WHEN_AWAY, NULL);
+
+	gtk_widget_show_all(b);
+	return b;
+}
+
+static gboolean
+config_dlg_key_cb(
+	GtkWidget * dlg_w, GdkEventKey * event,
+	struct config_dlg * dlg)
+{
+	if(event->keyval==GDK_Escape) {
+		destroy_config_dlg(&the_dlg);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/**
+ * config_dlg_response_handler:
+ *	handles user's response to the dialog
+ */
+static void
+config_dlg_response_handler(
+	GtkDialog * dialog,
+	gint response,
+	struct config_dlg * dlg)
+{
+	switch(response) {
+	case GTK_RESPONSE_OK:
+		if(dlg->is_changed)
+			set_config_from_dlg(dlg);
+		/* FALLTHROUGH */
+
+	case GTK_RESPONSE_DELETE_EVENT:
+	case GTK_RESPONSE_CANCEL:
+		destroy_config_dlg(&the_dlg);
+		break;
+
+	case GTK_RESPONSE_APPLY:
+		set_config_from_dlg(dlg);
+		sync_dlg_from_config(dlg);
+		break;
+
+	case GUI_RESPONSE_SAVE:
+		set_config_from_dlg(dlg);
+		sync_dlg_from_config(dlg);
+		raise_event(EVENT_IFACE_STORE_CONFIG, NULL, 0);
+		break;
+	}	
+}
+
+/*
+ * stores values from the dialog to the configuration
+ */
+static void
+set_config_from_dlg(struct config_dlg * dlg)
+{
+	/* signal that we are currently gathering
+	 *	configuration and dialog should not be updated
+	 *	(scattered) during this time
+	 */
+	dlg->gathering = TRUE;
+
+#define READ_TOGGLE_PREFS(p, t) \
+	prefs_set((p), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((t))))
+#define READ_SPIN_PREFS(p, s) \
+	prefs_set((p), (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(s)))
+#define READ_OPTION_PREFS(p, o) \
+	prefs_set((p), (guint)gtk_option_menu_get_history(GTK_OPTION_MENU(o)))
+#define READ_ENTRY_PREFS(p, e) \
+	prefs_set((p), gtk_entry_get_text(GTK_ENTRY((e))))
+#define READ_IPV4_ENTRY(p, e) do { \
+		guint32 ip; \
+		if(util_parse_ipv4(gtk_entry_get_text(GTK_ENTRY(e)), &ip)) \
+			prefs_set((p), ip); \
+		set_ipv4_entry((e), prefs_int(p)); \
+	} while(0)
+
+	/* Tray icon */
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_ENABLE, dlg->tray_enable_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP, dlg->tray_hide_on_startup_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE, dlg->tray_trigger_joinleave_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_CHANNEL, dlg->tray_trigger_channel_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_PRIVATE, dlg->tray_trigger_private_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_STATUS, dlg->tray_trigger_status_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_TOPIC, dlg->tray_trigger_topic_w);
+	READ_SPIN_PREFS(PREFS_GUI_TRAY_TOOLTIP_LINE_NUM, dlg->tray_tooltip_lines_w);
+
+	/* Idle */
+	READ_TOGGLE_PREFS(PREFS_IDLE_ENABLE, dlg->idle_enable_w);
+	READ_SPIN_PREFS(PREFS_IDLE_AUTO_AWAY, dlg->auto_away_w);
+	READ_SPIN_PREFS(PREFS_IDLE_AUTO_OFFLINE, dlg->auto_offline_w);
+
+	/* Pages */
+	READ_TOGGLE_PREFS(PREFS_GUI_TOPIC_BAR, dlg->pages_show_topic_entry);
+	READ_TOGGLE_PREFS(PREFS_GUI_PRESENT_ON_PRIVATE, dlg->pages_present_on_private);
+	READ_TOGGLE_PREFS(PREFS_MAIN_LOG_GLOBAL, dlg->pages_log_current_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT, dlg->pages_suppress_join_leave_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_RENAME_TEXT, dlg->pages_suppress_rename_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_MODE_TEXT, dlg->pages_suppress_mode_change_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_PRIVATE, dlg->date_private_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_CHANNEL, dlg->date_channel_w);
+	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_STATUS, dlg->date_status_w);
+	READ_OPTION_PREFS(PREFS_GUI_PAGE_TAB_POS, dlg->pages_notebook_pos_w);
+
+	/* Network */
+	READ_OPTION_PREFS(PREFS_NET_TYPE, dlg->net_type_w);
+	READ_SPIN_PREFS(PREFS_NET_PORT, dlg->net_port_w);
+	READ_ENTRY_PREFS(PREFS_NET_ENCODING, dlg->net_charset_w);
+	READ_ENTRY_PREFS(PREFS_NET_SECONDARY_ENCODING, dlg->net_charset2_w);	
+	READ_TOGGLE_PREFS(PREFS_NET_CHARSET_CHOICE, dlg->net_charset_choice_w);
+	READ_SPIN_PREFS(PREFS_USER_LIST_REFRESH, dlg->userlist_refresh_w);
+	READ_TOGGLE_PREFS(PREFS_NET_REPLY_INFO_REQ, dlg->net_reply_w);
+	READ_TOGGLE_PREFS(PREFS_NET_VERBOSE, dlg->net_log_w);
+	READ_TOGGLE_PREFS(PREFS_USER_KEEP_UNREPLIED, dlg->userlist_keep_unreplied_users_w);
+	READ_TOGGLE_PREFS(PREFS_NET_CHANNEL_NOTIFY, dlg->net_channel_greet_w);
+	READ_TOGGLE_PREFS(PREFS_NET_USE_MULTICAST, dlg->net_use_multicast_w);
+	READ_IPV4_ENTRY(PREFS_NET_BROADCAST_MASK, dlg->net_broadcast_w);
+	READ_IPV4_ENTRY(PREFS_NET_MULTICAST_ADDR, dlg->net_multicast_w);
+
+	/* Messages */
+	READ_TOGGLE_PREFS(PREFS_NET_IGNORE_MASS_MSG, dlg->msg_ignore_mass_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_MSG_CTRL_ENTER, dlg->msg_ctrl_return_w);
+	READ_TOGGLE_PREFS(
+		PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND, dlg->msg_show_messages_in_offline_dnd_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_MSG_IN_WINDOW, dlg->msg_show_window_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES, dlg->msg_minimize_mass_messages_w);
+	READ_TOGGLE_PREFS(PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES, dlg->msg_minimize_private_messages_w);
+	READ_SPIN_PREFS(PREFS_GUI_MSG_MAX_WINDOWS, dlg->msg_max_w);
+
+	/* Misc */
+	READ_TOGGLE_PREFS(PREFS_GUI_KEEP_SIZE, dlg->keep_window_size_w);
+	READ_TOGGLE_PREFS(PREFS_PREFS_AUTO_SAVE, dlg->save_on_exit_w);
+	READ_ENTRY_PREFS(PREFS_NET_MOTD, dlg->motd_w);
+	READ_ENTRY_PREFS(PREFS_NET_MOTD_WHEN_AWAY, dlg->motd_away_w);
+
+	/* change the apply button, to notify that the the dialog is now in sync with config
+	 * (however the config was not saved)
+	 */
+	set_config_dlg_modified(dlg, FALSE);
+
+	/* enable scattering of dialog */
+	dlg->gathering = FALSE;
+}
+
+/**
+ * syncs dialog with the current configuration values
+ */
+static void
+sync_dlg_from_config(struct config_dlg * dlg)
+{
+#define SET_SPIN_FROM_PREF(o, p) \
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(o), prefs_int(p))
+#define SET_TOGGLE_FROM_PREF(o, p) \
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o), prefs_bool(p))
+#define SET_OPTION_FROM_PREF(o, p) \
+	gtk_option_menu_set_history(GTK_OPTION_MENU(o), prefs_int(p))
+#define SET_ENTRY_FROM_PREF(o, p) \
+	gtk_entry_set_text(GTK_ENTRY(o), prefs_str(p))
+#define SET_IPV4_ENTRY_FROM_PREF(e, p) \
+	set_ipv4_entry((e), prefs_int(p))
+
+	/* Idle */
+	SET_TOGGLE_FROM_PREF(dlg->idle_enable_w, PREFS_IDLE_ENABLE);
+ 	SET_SPIN_FROM_PREF(dlg->auto_away_w, PREFS_IDLE_AUTO_AWAY);
+	SET_SPIN_FROM_PREF(dlg->auto_offline_w, PREFS_IDLE_AUTO_OFFLINE);
+	
+	/* Pages */
+	SET_TOGGLE_FROM_PREF(dlg->pages_show_topic_entry, PREFS_GUI_TOPIC_BAR);
+	SET_TOGGLE_FROM_PREF(dlg->pages_present_on_private, PREFS_GUI_PRESENT_ON_PRIVATE);
+	SET_TOGGLE_FROM_PREF(dlg->pages_log_current_w, PREFS_MAIN_LOG_GLOBAL);
+	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_join_leave_w, PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT);
+	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_rename_w, PREFS_SESS_SUPPRESS_RENAME_TEXT);
+	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_mode_change_w, PREFS_SESS_SUPPRESS_MODE_TEXT);
+	SET_TOGGLE_FROM_PREF(dlg->date_channel_w, PREFS_SESS_STAMP_CHANNEL);
+	SET_TOGGLE_FROM_PREF(dlg->date_private_w, PREFS_SESS_STAMP_PRIVATE);
+	SET_TOGGLE_FROM_PREF(dlg->date_status_w, PREFS_SESS_STAMP_STATUS);
+	SET_OPTION_FROM_PREF(dlg->pages_notebook_pos_w, PREFS_GUI_PAGE_TAB_POS);
+
+	/* Misc */
+	SET_TOGGLE_FROM_PREF(dlg->keep_window_size_w, PREFS_GUI_KEEP_SIZE);
+	SET_TOGGLE_FROM_PREF(dlg->save_on_exit_w, PREFS_PREFS_AUTO_SAVE);
+	SET_ENTRY_FROM_PREF(dlg->motd_w, PREFS_NET_MOTD);
+	SET_ENTRY_FROM_PREF(dlg->motd_away_w, PREFS_NET_MOTD_WHEN_AWAY);
+
+	/* Tray icon */
+	SET_TOGGLE_FROM_PREF(dlg->tray_enable_w, PREFS_GUI_TRAY_ENABLE);
+	systray_pref_gui_tray_enable_toggled_cb(
+		GTK_TOGGLE_BUTTON(dlg->tray_enable_w), (gpointer)dlg);
+	SET_TOGGLE_FROM_PREF(dlg->tray_hide_on_startup_w, PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP);
+	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_joinleave_w, PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE);
+	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_channel_w, PREFS_GUI_TRAY_TRIGGERS_CHANNEL);
+	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_private_w, PREFS_GUI_TRAY_TRIGGERS_PRIVATE);
+	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_status_w, PREFS_GUI_TRAY_TRIGGERS_STATUS);
+	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_topic_w, PREFS_GUI_TRAY_TRIGGERS_TOPIC);
+	SET_SPIN_FROM_PREF(dlg->tray_tooltip_lines_w, PREFS_GUI_TRAY_TOOLTIP_LINE_NUM);
+
+	/* Network */
+	SET_OPTION_FROM_PREF(dlg->net_type_w, PREFS_NET_TYPE);
+	SET_SPIN_FROM_PREF(dlg->net_port_w, PREFS_NET_PORT);
+	SET_ENTRY_FROM_PREF(dlg->net_charset_w, PREFS_NET_ENCODING);
+	SET_ENTRY_FROM_PREF(dlg->net_charset2_w, PREFS_NET_SECONDARY_ENCODING);	
+	SET_TOGGLE_FROM_PREF(dlg->net_charset_choice_w, PREFS_NET_CHARSET_CHOICE);
+	SET_TOGGLE_FROM_PREF(dlg->net_reply_w, PREFS_NET_REPLY_INFO_REQ);
+	SET_TOGGLE_FROM_PREF(dlg->net_log_w, PREFS_NET_VERBOSE);
+	SET_TOGGLE_FROM_PREF(dlg->net_channel_greet_w, PREFS_NET_CHANNEL_NOTIFY);
+	SET_TOGGLE_FROM_PREF(dlg->net_use_multicast_w, PREFS_NET_USE_MULTICAST);
+	SET_IPV4_ENTRY_FROM_PREF(dlg->net_broadcast_w, PREFS_NET_BROADCAST_MASK);
+	SET_IPV4_ENTRY_FROM_PREF(dlg->net_multicast_w, PREFS_NET_MULTICAST_ADDR);
+
+	/* User list settings */
+	SET_TOGGLE_FROM_PREF(dlg->userlist_keep_unreplied_users_w, PREFS_USER_KEEP_UNREPLIED);
+	SET_SPIN_FROM_PREF(dlg->userlist_refresh_w, PREFS_USER_LIST_REFRESH);
+
+	/* Message settings */
+	SET_TOGGLE_FROM_PREF(dlg->msg_ignore_mass_w, PREFS_NET_IGNORE_MASS_MSG);
+	SET_TOGGLE_FROM_PREF(dlg->msg_ctrl_return_w, PREFS_GUI_MSG_CTRL_ENTER);
+	SET_TOGGLE_FROM_PREF(
+		dlg->msg_show_messages_in_offline_dnd_w, PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND);
+	SET_TOGGLE_FROM_PREF(dlg->msg_show_window_w, PREFS_GUI_MSG_IN_WINDOW);
+	SET_TOGGLE_FROM_PREF(dlg->msg_minimize_mass_messages_w, PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES);
+	SET_TOGGLE_FROM_PREF(dlg->msg_minimize_private_messages_w, PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES);
+	
+	SET_SPIN_FROM_PREF(dlg->msg_max_w, PREFS_GUI_MSG_MAX_WINDOWS);
+	messages_pref_in_window_toggled_cb(
+		GTK_TOGGLE_BUTTON(dlg->msg_show_window_w), (gpointer)dlg);
+	
+	/* these settings are 'current' - disable the `Save' button */
+	set_config_dlg_modified(dlg, FALSE);
+}
+
+static void
+config_dlg_prefs_tree_selection_changed_cb(
+	GtkTreeSelection * selection, struct config_dlg * dlg)
+{
+	GtkTreeIter iter;
+	GtkTreeModel * model;
+	gint index;
+
+	if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
+		gtk_tree_model_get(model, &iter, CONFIG_TREE_INDEX, &index, -1);
+
+		if(index >= 0)
+			gtk_notebook_set_current_page(GTK_NOTEBOOK(dlg->notebook_w), index);
+	}
+}
+
+static void 
+show_config_dlg(struct config_dlg ** pdlg)
+{
+	struct config_dlg * dlg;
+	GtkWidget * hbox, * scrolled;
+	GtkCellRenderer * cell;
+	GtkTreeViewColumn * column;
+	GtkTreeSelection * selection;
+	GtkTreeIter iter;
+
+	if(*pdlg) return;
+	
+	*pdlg = dlg = g_malloc(sizeof(struct config_dlg));
+
+	dlg->is_changed = FALSE;
+	dlg->gathering = FALSE;
+
+	/* create config dlg and setup signals */
+	dlg->dlg_w = gtk_dialog_new_with_buttons(_("Preferences"), gui_get_main_window(), 0, NULL);
+
+	gtk_dialog_add_button(GTK_DIALOG(dlg->dlg_w), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+	dlg->save_w = gtk_dialog_add_button(
+			GTK_DIALOG(dlg->dlg_w), GTK_STOCK_SAVE, GUI_RESPONSE_SAVE);
+	gtk_button_box_set_child_secondary(
+			GTK_BUTTON_BOX(GTK_DIALOG(dlg->dlg_w)->action_area), dlg->save_w, TRUE);
+	dlg->apply_w = gtk_dialog_add_button(
+			GTK_DIALOG(dlg->dlg_w), GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
+	gtk_dialog_add_button(GTK_DIALOG(dlg->dlg_w), GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+	g_signal_connect(G_OBJECT(dlg->dlg_w), "response",
+		G_CALLBACK(config_dlg_response_handler), (gpointer)dlg);
+	g_signal_connect(G_OBJECT(dlg->dlg_w), "delete-event",
+		G_CALLBACK(gtk_true), NULL);
+	g_signal_connect(G_OBJECT(dlg->dlg_w), "key-press-event",
+		G_CALLBACK(config_dlg_key_cb), (gpointer)dlg);
+
+	/* make hbox for a tree and the notebook */
+	hbox = gtk_hbox_new(FALSE, 2);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg->dlg_w)->vbox), hbox, TRUE, TRUE, 0);
+
+	/* setup prefs tree and insert into the dialog */
+	dlg->prefs_tree_store = gtk_tree_store_new(CONFIG_TREE_NUM, G_TYPE_STRING, G_TYPE_INT);
+
+	dlg->prefs_tree_w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dlg->prefs_tree_store));
+	gtk_widget_set_size_request(dlg->prefs_tree_w, 150, -1);
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dlg->prefs_tree_w), FALSE);
+
+	/* add pref name renderer */
+	cell = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(
+			"Preference", cell,
+			"text", CONFIG_TREE_NAME, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(dlg->prefs_tree_w), column);
+
+	/* connect signals */
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->prefs_tree_w));
+	g_signal_connect(
+		G_OBJECT(selection), "changed",
+		G_CALLBACK(config_dlg_prefs_tree_selection_changed_cb), dlg);
+
+	scrolled = gtk_scrolled_window_new(FALSE, FALSE);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(
+		GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
+	gtk_container_add(GTK_CONTAINER(scrolled), dlg->prefs_tree_w);
+
+	/* setup notebook and insert it into the dialog */
+	dlg->notebook_w = gtk_notebook_new();
+	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(dlg->notebook_w), FALSE);
+	gtk_notebook_set_show_border(GTK_NOTEBOOK(dlg->notebook_w), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox), dlg->notebook_w, TRUE, TRUE, 0);
+
+	gtk_widget_show_all(hbox);
+
+	/* add configuration pages */
+#define ADD_PAGE(name, frame) do { \
+		gint index = gtk_notebook_append_page( \
+			GTK_NOTEBOOK(dlg->notebook_w), (frame), NULL); \
+		gtk_tree_store_append(dlg->prefs_tree_store, &iter, NULL); \
+		gtk_tree_store_set( \
+			dlg->prefs_tree_store, &iter, \
+			CONFIG_TREE_NAME, (name), CONFIG_TREE_INDEX, index, -1); \
+	} while(0)
+
+	ADD_PAGE(_("Network settings"), make_net_frame(dlg));
+	ADD_PAGE(_("User list"), make_user_list_frame(dlg));
+	ADD_PAGE(_("Pages"), make_pages_frame(dlg));
+	ADD_PAGE(_("Messages"), make_messages_frame(dlg));
+	ADD_PAGE(_("Tray icon"), make_systray_frame(dlg));
+	ADD_PAGE(_("Idle"), make_idle_frame(dlg));
+	ADD_PAGE(_("Miscellaneous"), make_settings_frame(dlg));
+
+	/* show the window */
+	gtk_window_present(GTK_WINDOW(dlg->dlg_w));
+	gtk_widget_set_sensitive(dlg->save_w, !prefs_in_sync());
+}
+
+static void
+set_config_dlg_modified(struct config_dlg * dlg, gboolean is_changed)
+{
+	gtk_widget_set_sensitive(dlg->apply_w, is_changed);
+	if(is_changed)
+		gtk_widget_set_sensitive(dlg->save_w, is_changed);
+			
+	dlg->is_changed = is_changed;
+}
+
+static void
+destroy_config_dlg(struct config_dlg ** pdlg)
+{
+	if(*pdlg) {
+		g_object_unref((*pdlg)->prefs_tree_store);
+		gtk_widget_destroy((*pdlg)->dlg_w);
+
+		g_free(*pdlg);
+		*pdlg = NULL;
+	}
+}
+
+static void
+gui_config_event_cb(enum app_event_enum e, gpointer p, gint i)
+{
+	switch(e) {
+	case EVENT_MAIN_INIT:
+		the_dlg = NULL;
+		break;
+
+	case EVENT_MAIN_PRECLOSE:
+		destroy_config_dlg(&the_dlg);
+		break;
+		
+	case EVENT_PREFS_CHANGED:
+		/* update dialog, if not currently gathering */
+		if(the_dlg && !the_dlg->gathering)
+			sync_dlg_from_config(the_dlg);
+		break;
+
+	case EVENT_PREFS_SAVED:
+		/* disable 'Save' button, as the configuration now is in sync
+		 */
+		if(the_dlg)
+			gtk_widget_set_sensitive(the_dlg->save_w, FALSE);
+		break;
+	case EVENT_IFACE_SHOW_CONFIGURE_DLG:
+		/* make & show dialog */
+		show_config_dlg(&the_dlg);
+		sync_dlg_from_config(the_dlg);
+		break;
+	default:
+		break;	/* nothing */
+	}
+}
+
+/** exported routines
+  *****************************************/
+void gui_config_dlg_register()
+{
+	register_event_cb(
+		gui_config_event_cb,
+		EVENT_MAIN|EVENT_PREFS|EVENT_IFACE);
 }
-
-static void
-prefs_dlg_check_button_toggled_cb(GtkToggleButton * togglebutton_w, gpointer dlg)
-{
-	/* update dialog state */
-	set_config_dlg_modified(PCONFIG_DLG(dlg), TRUE);
-}
-
-static GtkWidget *
-add_check_button(
-	struct config_dlg * dlg,
-	GtkWidget * b, const gchar * prefs_name,
-	GCallback toggled_cb, gpointer toggled_cb_user_data)
-{
-	GtkWidget * w;
-
-	w = gtk_check_button_new_with_mnemonic(prefs_description(prefs_name));
-	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 0);
-
-	g_signal_connect(
-		G_OBJECT(w), "toggled",
-		G_CALLBACK(prefs_dlg_check_button_toggled_cb), (gpointer)dlg);
-
-	if(toggled_cb)
-		g_signal_connect(G_OBJECT(w), "toggled", toggled_cb, toggled_cb_user_data);
-
-	return w;
-}
-
-static void
-prefs_dlg_spin_button_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
-{
-	/* update dialog state */
-	set_config_dlg_modified(PCONFIG_DLG(dlg), TRUE);
-}
-
-static GtkWidget *
-add_spin_button(
-	struct config_dlg * dlg,
-	GtkWidget * b,
-	const gchar * prefs_name,
-	int min, int max,
-	GtkWidget ** p_label_w,
-	GCallback value_changed_cb,
-	gpointer value_changed_cb_data)
-{
-	GtkWidget * w, * hb, * label_w;
-
-	g_assert(dlg && b && min<max);
-
-	hb = gtk_hbox_new(FALSE, 2);
-	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
-
-	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
-	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
-	if(p_label_w)
-		*p_label_w = label_w;
-
-	w = gtk_spin_button_new_with_range(min, max, 1);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), w);
-	gtk_box_pack_start(GTK_BOX(hb), w, FALSE, FALSE, 0);
-
-	g_signal_connect(
-		G_OBJECT(w), "value-changed",
-		G_CALLBACK(prefs_dlg_spin_button_changed_cb), (gpointer)dlg);
-
-	if(value_changed_cb)
-		g_signal_connect(
-			G_OBJECT(w), "value-changed",
-			G_CALLBACK(value_changed_cb), value_changed_cb_data);
-
-	return w;
-}
-
-static void
-prefs_dlg_option_changed_cb(GtkOptionMenu * o, struct config_dlg * dlg)
-{
-	set_config_dlg_modified(dlg, TRUE);
-}
-
-static GtkWidget *
-add_option(
-	struct config_dlg * dlg,
-	GtkWidget * b,
-	const gchar * prefs_name,
-	GList * entries,
-	GtkWidget ** p_label_w)
-{
-	GtkWidget * o, * hb, * menu_w, * label_w;
-
-	g_assert(b && entries);
-
-	hb = gtk_hbox_new(FALSE, 2);
-	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
-
-	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
-	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
-	if(p_label_w) *p_label_w = label_w;
-
-	/* make option menu */
-	o = gtk_option_menu_new();
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), o);
-	menu_w = gtk_menu_new();
-	for(; entries; entries = entries->next) {
-		gtk_menu_shell_append(
-			GTK_MENU_SHELL(menu_w),
-			gtk_menu_item_new_with_mnemonic((gchar*)entries->data));
-	}
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(o), menu_w);
-	gtk_box_pack_start(GTK_BOX(hb), o, FALSE, FALSE, 0);
-
-	g_signal_connect(G_OBJECT(o), "changed", G_CALLBACK(prefs_dlg_option_changed_cb), dlg);
-
-	return o;
-}
-
-static void
-prefs_dlg_entry_changed_cb(GtkEntry * w, struct config_dlg * dlg)
-{
-	set_config_dlg_modified(dlg, TRUE);
-}
-
-static GtkWidget *
-add_entry(
-	struct config_dlg * dlg,
-	GtkWidget * b,
-	const gchar * prefs_name,
-	GtkWidget ** p_label_w)
-{
-	GtkWidget * hb, * w, * label_w;
-
-	hb = gtk_hbox_new(FALSE, 2);
-	gtk_box_pack_start(GTK_BOX(b), hb, FALSE, FALSE, 0);
-
-	/* make label */
-	label_w = gtk_label_new_with_mnemonic(prefs_description(prefs_name));
-	gtk_box_pack_start(GTK_BOX(hb), label_w, FALSE, FALSE, 0);
-	if(p_label_w) *p_label_w = label_w;
-
-	/* make edit entry */
-	w = gtk_entry_new();
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label_w), w);
-	gtk_box_pack_start(GTK_BOX(hb), w, TRUE, TRUE, 0);
-	g_signal_connect(
-		G_OBJECT(w), "changed",
-		G_CALLBACK(prefs_dlg_entry_changed_cb), (gpointer)dlg);
-
-	return w;
-}
-
-static GtkWidget *
-add_widget(
-	struct config_dlg * dlg,
-	GtkWidget * frame_vbox,
-	const gchar * label_text, GtkWidget * widget)
-{
-	GtkWidget * hbox = gtk_hbox_new(FALSE, 2);
-
-	if(label_text) {
-		gtk_box_pack_start(
-			GTK_BOX(hbox), gtk_label_new_with_mnemonic(label_text),
-			FALSE, FALSE, 0);
-	}
-	gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(frame_vbox), hbox, FALSE, FALSE, 0);
-
-	return widget;
-}
-
-/* gtk 2.4+ has support for encoding combo widget
- */
-#if(HAVE_ENCODING_COMBO_WIDGET)
-
-static GtkWidget *
-net_frame_encoding_combo(
-	struct config_dlg * dlg,
-	const gchar * label_text)
-{
-	GtkWidget * combo_w;
-	const gchar ** encoding;
-	gboolean have_current_encoding;
-
-	combo_w = gtk_combo_box_entry_new_text();
-
-	/* add encodings to the combo box list */
-	have_current_encoding = FALSE;
-	for(encoding = supported_encodings; *encoding; encoding++) {
-		/* check encoding is supported on this system/glib */
-		gchar *enc_test = g_convert("a", 1, "UTF-8", *encoding, NULL,NULL,NULL);
-		if(!enc_test)
-			continue;
-		g_free(enc_test);
-
-		gtk_combo_box_append_text(GTK_COMBO_BOX(combo_w), *encoding);
-
-		/* check if this is the current encoding */
-		if(!g_utf8_collate(*encoding, prefs_str(PREFS_NET_ENCODING)))
-			have_current_encoding = TRUE;
-	}
-	if(!have_current_encoding) {
-		/* add the default encoding as it was not found in the list */
-		gtk_combo_box_prepend_text(GTK_COMBO_BOX(combo_w), prefs_str(PREFS_NET_ENCODING));
-	}
-
-	return combo_w;
-}
-#endif
-
-static void
-net_detect_btn_clicked(GtkButton * button_w, struct config_dlg * dlg)
-{
-	raise_event(EVENT_IFACE_SHOW_NETDETECT_DLG, NULL, 0);
-}
-
-static void
-net_prefs_type_changed_cb(gint mode, gpointer userdata)
-{
-	struct config_dlg * dlg = (struct config_dlg *)userdata;
-
-	set_config_dlg_modified(dlg, TRUE);
-
-	if(mode==NET_TYPE_QCHAT) {
-		/* there's no option for multicast in quickchat mode */
-		gtk_widget_set_sensitive(dlg->net_use_multicast_w, FALSE);
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dlg->net_use_multicast_w), FALSE);
-	} else {
-		gtk_widget_set_sensitive(dlg->net_use_multicast_w, TRUE);
-	}
-}
-
-static void
-net_prefs_use_multicast_changed_cb(GtkToggleButton * button_w, struct config_dlg * dlg)
-{
-	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
-	
-	gtk_widget_set_sensitive(dlg->net_broadcast_label_w, !set);
-	gtk_widget_set_sensitive(dlg->net_broadcast_w, !set);
-
-	gtk_widget_set_sensitive(dlg->net_multicast_label_w, set);
-	gtk_widget_set_sensitive(dlg->net_multicast_w, set);
-}
-
-static GtkWidget *
-make_net_frame(struct config_dlg * dlg)
-{
-	GtkWidget * b, * detect_btn;
-
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	/* network type option menu */
-	dlg->net_type_w = add_widget(
-		dlg, b, prefs_description(PREFS_NET_TYPE),
-		util_net_type_option(net_prefs_type_changed_cb, (gpointer)dlg));
-
-	/* network port numer */
-	dlg->net_port_w = add_spin_button(dlg, b, PREFS_NET_PORT, 0, 65535, NULL, NULL, NULL);
-
-	/* brodcast & multicast addresses */
-	dlg->net_use_multicast_w = add_check_button(
-		dlg, b, PREFS_NET_USE_MULTICAST,
-		G_CALLBACK(net_prefs_use_multicast_changed_cb), (gpointer)dlg);
-	dlg->net_broadcast_w = add_entry(dlg, b, PREFS_NET_BROADCAST_MASK, &dlg->net_broadcast_label_w);
-	dlg->net_multicast_w = add_entry(dlg, b, PREFS_NET_MULTICAST_ADDR, &dlg->net_multicast_label_w);
-	net_prefs_use_multicast_changed_cb(GTK_TOGGLE_BUTTON(dlg->net_use_multicast_w), dlg);
-	net_prefs_type_changed_cb(
-		gtk_option_menu_get_history(GTK_OPTION_MENU(dlg->net_type_w)), dlg);
-
-	/* net charset selection widget */
-#if(HAVE_ENCODING_COMBO_WIDGET)
-	dlg->net_charset_combo_w = add_widget(
-		dlg, b, prefs_description(PREFS_NET_ENCODING),
-		net_frame_encoding_combo(dlg, prefs_description(PREFS_NET_ENCODING)));
-
-	dlg->net_charset_w = GTK_BIN(dlg->net_charset_combo_w)->child;
-	g_signal_connect(G_OBJECT(dlg->net_charset_w),
-		"changed", G_CALLBACK(prefs_dlg_entry_changed_cb), (gpointer) dlg);
-#else
-	dlg->net_charset_w = add_entry(dlg, b, PREFS_NET_ENCODING, NULL);
-#endif
-
-	/* automatic detection button */
-	detect_btn = gtk_button_new_with_mnemonic(_("Detect available networks.."));
-	g_signal_connect(G_OBJECT(detect_btn), "clicked",
-		G_CALLBACK(net_detect_btn_clicked), (gpointer)dlg);
-	add_widget(dlg, b, NULL, detect_btn);
-
-	/* separator for miscelanious settings */
-	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 8);
-
-	/* whether to notify buddy/channel of our joins/leaves */
-	dlg->net_channel_greet_w = add_check_button(dlg, b, PREFS_NET_CHANNEL_NOTIFY, NULL, NULL);
-
-	/* whether to reply to info requests */
-	dlg->net_reply_w = add_check_button(dlg, b, PREFS_NET_REPLY_INFO_REQ, NULL, NULL);
-
-	/* whether to log network events verbosely */
-	dlg->net_log_w = add_check_button(dlg, b, PREFS_NET_VERBOSE, NULL, NULL);
-
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static GtkWidget *
-make_user_list_frame(struct config_dlg * dlg)
-{
-	GtkWidget * b;
-
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	/* update interval selection */
-	dlg->userlist_refresh_w
-		= add_spin_button(dlg, b, PREFS_USER_LIST_REFRESH, 1, 1000, NULL, NULL, NULL);
-
-	/* whether to remove dead users from the list */
-	dlg->userlist_keep_unreplied_users_w
-		= add_check_button(dlg, b, PREFS_USER_KEEP_UNREPLIED, NULL, NULL);
-
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static void
-idle_prefs_idle_auto_away_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
-{
-	gint away, offl;
-
-	offl = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w));
-	away = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w));
-
-	/* make sure away timeout is not larger than that of offline */
-	if(away > offl)
-		gtk_spin_button_set_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w), away);
-}
-
-static void
-idle_prefs_idle_auto_offline_changed_cb(GtkSpinButton * spinbutton_w, gpointer dlg)
-{
-	gint away, offl;
-
-	offl = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_offline_w));
-	away = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w));
-
-	/* make sure offline timeout is larger away's */
-	if(offl < away)
-		gtk_spin_button_set_value(GTK_SPIN_BUTTON(PCONFIG_DLG(dlg)->auto_away_w), offl);
-}
-
-static void
-idle_prefs_idle_enabled_changed_cb(GtkToggleButton * togglebutton_w, gpointer dlg)
-{
-	gboolean set = gtk_toggle_button_get_active(togglebutton_w);
-
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->auto_away_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->auto_offline_w, set);
-}
-
-static GtkWidget *
-make_idle_frame(struct config_dlg * dlg)
-{
-	GtkWidget * box;
-
-	box = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(box), GEOM_DLG_PAGE_BORDER);
-
-	/* insert enabler/disabler */
-	dlg->idle_enable_w = add_check_button(
-		dlg, box, PREFS_IDLE_ENABLE,
-		G_CALLBACK(idle_prefs_idle_enabled_changed_cb), (gpointer)dlg);
-
-	/* insert auto-away & auto-offline */
-	dlg->auto_away_w = add_spin_button(
-		dlg, box, PREFS_IDLE_AUTO_AWAY, 1, 240, NULL,
-		G_CALLBACK(idle_prefs_idle_auto_away_changed_cb), (gpointer)dlg);
-	dlg->auto_offline_w = add_spin_button(
-		dlg, box, PREFS_IDLE_AUTO_OFFLINE, 1, 240, NULL,
-		G_CALLBACK(idle_prefs_idle_auto_offline_changed_cb), (gpointer)dlg);
-
-	gtk_widget_show_all(box);
-	return box;
-}
-
-static void
-messages_pref_in_window_toggled_cb(GtkToggleButton * button_w, gpointer dlg)
-{
-	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
-
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->msg_max_label_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->msg_max_w, set);
-}
-
-static GtkWidget *
-make_messages_frame(struct config_dlg * dlg)
-{
-	GtkWidget * b;
-
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	dlg->msg_ignore_mass_w = add_check_button(dlg, b, PREFS_NET_IGNORE_MASS_MSG, NULL, NULL);
-	dlg->msg_ctrl_return_w = add_check_button(dlg, b, PREFS_GUI_MSG_CTRL_ENTER, NULL, NULL);
-	dlg->msg_show_messages_in_offline_dnd_w =
-		add_check_button(dlg, b, PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND, NULL, NULL);
-
-	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
-
-	dlg->msg_show_window_w = add_check_button(
-		dlg, b, PREFS_GUI_MSG_IN_WINDOW,
-		G_CALLBACK(messages_pref_in_window_toggled_cb), (gpointer)dlg);
-
-	dlg->msg_max_w = add_spin_button(
-		dlg, b, PREFS_GUI_MSG_MAX_WINDOWS,
-		1, 64, &dlg->msg_max_label_w, NULL, NULL);
-
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static GtkWidget *
-make_pages_frame(struct config_dlg * dlg)
-{
-	GList * pos_list;
-	GtkWidget * b;
-
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	dlg->pages_show_topic_entry = add_check_button(dlg, b, PREFS_GUI_TOPIC_BAR, NULL, NULL);
-
-	/* whether to present (show on top) main window when someone
-	 * opens private chat with us */
-	dlg->pages_present_on_private = add_check_button(
-		dlg, b, PREFS_GUI_PRESENT_ON_PRIVATE, NULL, NULL);
-
-	/* whether to duplicate new "Status" tab messages
-	 * in active sessions */
-	dlg->pages_log_current_w = add_check_button(dlg, b, PREFS_MAIN_LOG_GLOBAL, NULL, NULL);
-
-	/* add page notebook tab position option
-	 * (the order should be the same as in `enum GtkPositionType')
-	 */
-	pos_list = g_list_append(NULL, _("Left"));
-	pos_list = g_list_append(pos_list, _("Right"));
-	pos_list = g_list_append(pos_list, _("Top"));
-	pos_list = g_list_append(pos_list, _("Bottom"));
-	dlg->pages_notebook_pos_w = add_option(dlg, b, PREFS_GUI_PAGE_TAB_POS, pos_list, NULL);
-	g_list_free(pos_list);
-
-	/* message suppress settings */
-	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
-	dlg->pages_suppress_join_leave_w = add_check_button(
-		dlg, b, PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT, NULL, NULL);
-	dlg->pages_suppress_rename_w = add_check_button(
-		dlg, b, PREFS_SESS_SUPPRESS_RENAME_TEXT, NULL, NULL);
-	dlg->pages_suppress_mode_change_w = add_check_button(
-		dlg, b, PREFS_SESS_SUPPRESS_MODE_TEXT, NULL, NULL);
-
-	/* time stamp settings */
-	gtk_box_pack_start(GTK_BOX(b), gtk_hseparator_new(), FALSE, FALSE, 6);
-
-	dlg->date_channel_w = add_check_button(dlg, b, PREFS_SESS_STAMP_CHANNEL, NULL, NULL);
-	dlg->date_private_w = add_check_button(dlg, b, PREFS_SESS_STAMP_PRIVATE, NULL, NULL);
-	dlg->date_status_w = add_check_button(dlg, b, PREFS_SESS_STAMP_STATUS, NULL, NULL);
-
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static void
-systray_pref_gui_tray_enable_toggled_cb(GtkToggleButton * button_w, gpointer dlg)
-{
-	gboolean set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button_w));
-
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_hide_on_startup_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_joinleave_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_topic_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_status_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_private_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_trigger_channel_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_tooltip_lines_w, set);
-	gtk_widget_set_sensitive(PCONFIG_DLG(dlg)->tray_tooltip_lines_label_w, set);
-}
-
-static GtkWidget *
-make_systray_frame(struct config_dlg * dlg)
-{
-	GtkWidget * b, * w;
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	dlg->tray_enable_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_ENABLE,
-		G_CALLBACK(systray_pref_gui_tray_enable_toggled_cb), (gpointer)dlg);
-
-	dlg->tray_hide_on_startup_w
-		= add_check_button(dlg, b, PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP, NULL, NULL);
-
-	w = gtk_hseparator_new();
-	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 8);
-
-	dlg->tray_trigger_joinleave_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE, NULL, NULL);
-	dlg->tray_trigger_channel_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_TRIGGERS_CHANNEL, NULL, NULL);
-	dlg->tray_trigger_private_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_TRIGGERS_PRIVATE, NULL, NULL);
-	dlg->tray_trigger_status_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_TRIGGERS_STATUS, NULL, NULL);
-	dlg->tray_trigger_topic_w = add_check_button(
-		dlg, b, PREFS_GUI_TRAY_TRIGGERS_TOPIC, NULL, NULL);
-
-	w = gtk_hseparator_new();
-	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 8);
-
-	dlg->tray_tooltip_lines_w = add_spin_button(
-		dlg, b, PREFS_GUI_TRAY_TOOLTIP_LINE_NUM,
-		0, 32, & dlg->tray_tooltip_lines_label_w, NULL, NULL);
-		
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static GtkWidget *
-make_settings_frame(struct config_dlg * dlg)
-{
-	GtkWidget * b, * w;
-
-	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(b), GEOM_DLG_PAGE_BORDER);
-
-	/* add other settings
-	 */
-	dlg->keep_window_size_w = add_check_button(dlg, b, PREFS_GUI_KEEP_SIZE, NULL, NULL);
-	dlg->save_on_exit_w = add_check_button(dlg, b, PREFS_PREFS_AUTO_SAVE, NULL, NULL);
-
-	w = gtk_hseparator_new();
-	gtk_box_pack_start(GTK_BOX(b), w, FALSE, FALSE, 0);
-
-	dlg->motd_w = add_entry(dlg, b, PREFS_NET_MOTD, NULL);
-	dlg->motd_away_w = add_entry(dlg, b, PREFS_NET_MOTD_WHEN_AWAY, NULL);
-
-	gtk_widget_show_all(b);
-	return b;
-}
-
-static gboolean
-config_dlg_key_cb(
-	GtkWidget * dlg_w, GdkEventKey * event,
-	struct config_dlg * dlg)
-{
-	if(event->keyval==GDK_Escape) {
-		destroy_config_dlg(&the_dlg);
-		return TRUE;
-	}
-	return FALSE;
-}
-
-/**
- * config_dlg_response_handler:
- *	handles user's response to the dialog
- */
-static void
-config_dlg_response_handler(
-	GtkDialog * dialog,
-	gint response,
-	struct config_dlg * dlg)
-{
-	switch(response) {
-	case GTK_RESPONSE_OK:
-		if(dlg->is_changed)
-			set_config_from_dlg(dlg);
-		/* FALLTHROUGH */
-
-	case GTK_RESPONSE_DELETE_EVENT:
-	case GTK_RESPONSE_CANCEL:
-		destroy_config_dlg(&the_dlg);
-		break;
-
-	case GTK_RESPONSE_APPLY:
-		set_config_from_dlg(dlg);
-		sync_dlg_from_config(dlg);
-		break;
-
-	case GUI_RESPONSE_SAVE:
-		set_config_from_dlg(dlg);
-		sync_dlg_from_config(dlg);
-		raise_event(EVENT_IFACE_STORE_CONFIG, NULL, 0);
-		break;
-	}	
-}
-
-/*
- * stores values from the dialog to the configuration
- */
-static void
-set_config_from_dlg(struct config_dlg * dlg)
-{
-	/* signal that we are currently gathering
-	 *	configuration and dialog should not be updated
-	 *	(scattered) during this time
-	 */
-	dlg->gathering = TRUE;
-
-#define READ_TOGGLE_PREFS(p, t) \
-	prefs_set((p), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((t))))
-#define READ_SPIN_PREFS(p, s) \
-	prefs_set((p), (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(s)))
-#define READ_OPTION_PREFS(p, o) \
-	prefs_set((p), (guint)gtk_option_menu_get_history(GTK_OPTION_MENU(o)))
-#define READ_ENTRY_PREFS(p, e) \
-	prefs_set((p), gtk_entry_get_text(GTK_ENTRY((e))))
-#define READ_IPV4_ENTRY(p, e) do { \
-		guint32 ip; \
-		if(util_parse_ipv4(gtk_entry_get_text(GTK_ENTRY(e)), &ip)) \
-			prefs_set((p), ip); \
-		set_ipv4_entry((e), prefs_int(p)); \
-	} while(0)
-
-	/* Tray icon */
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_ENABLE, dlg->tray_enable_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP, dlg->tray_hide_on_startup_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE, dlg->tray_trigger_joinleave_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_CHANNEL, dlg->tray_trigger_channel_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_PRIVATE, dlg->tray_trigger_private_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_STATUS, dlg->tray_trigger_status_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_TRAY_TRIGGERS_TOPIC, dlg->tray_trigger_topic_w);
-	READ_SPIN_PREFS(PREFS_GUI_TRAY_TOOLTIP_LINE_NUM, dlg->tray_tooltip_lines_w);
-
-	/* Idle */
-	READ_TOGGLE_PREFS(PREFS_IDLE_ENABLE, dlg->idle_enable_w);
-	READ_SPIN_PREFS(PREFS_IDLE_AUTO_AWAY, dlg->auto_away_w);
-	READ_SPIN_PREFS(PREFS_IDLE_AUTO_OFFLINE, dlg->auto_offline_w);
-
-	/* Pages */
-	READ_TOGGLE_PREFS(PREFS_GUI_TOPIC_BAR, dlg->pages_show_topic_entry);
-	READ_TOGGLE_PREFS(PREFS_GUI_PRESENT_ON_PRIVATE, dlg->pages_present_on_private);
-	READ_TOGGLE_PREFS(PREFS_MAIN_LOG_GLOBAL, dlg->pages_log_current_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT, dlg->pages_suppress_join_leave_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_RENAME_TEXT, dlg->pages_suppress_rename_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_SUPPRESS_MODE_TEXT, dlg->pages_suppress_mode_change_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_PRIVATE, dlg->date_private_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_CHANNEL, dlg->date_channel_w);
-	READ_TOGGLE_PREFS(PREFS_SESS_STAMP_STATUS, dlg->date_status_w);
-	READ_OPTION_PREFS(PREFS_GUI_PAGE_TAB_POS, dlg->pages_notebook_pos_w);
-
-	/* Network */
-	READ_OPTION_PREFS(PREFS_NET_TYPE, dlg->net_type_w);
-	READ_SPIN_PREFS(PREFS_NET_PORT, dlg->net_port_w);
-	READ_ENTRY_PREFS(PREFS_NET_ENCODING, dlg->net_charset_w);
-	READ_SPIN_PREFS(PREFS_USER_LIST_REFRESH, dlg->userlist_refresh_w);
-	READ_TOGGLE_PREFS(PREFS_NET_REPLY_INFO_REQ, dlg->net_reply_w);
-	READ_TOGGLE_PREFS(PREFS_NET_VERBOSE, dlg->net_log_w);
-	READ_TOGGLE_PREFS(PREFS_USER_KEEP_UNREPLIED, dlg->userlist_keep_unreplied_users_w);
-	READ_TOGGLE_PREFS(PREFS_NET_CHANNEL_NOTIFY, dlg->net_channel_greet_w);
-	READ_TOGGLE_PREFS(PREFS_NET_USE_MULTICAST, dlg->net_use_multicast_w);
-	READ_IPV4_ENTRY(PREFS_NET_BROADCAST_MASK, dlg->net_broadcast_w);
-	READ_IPV4_ENTRY(PREFS_NET_MULTICAST_ADDR, dlg->net_multicast_w);
-
-	/* Messages */
-	READ_TOGGLE_PREFS(PREFS_NET_IGNORE_MASS_MSG, dlg->msg_ignore_mass_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_MSG_CTRL_ENTER, dlg->msg_ctrl_return_w);
-	READ_TOGGLE_PREFS(
-		PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND, dlg->msg_show_messages_in_offline_dnd_w);
-	READ_TOGGLE_PREFS(PREFS_GUI_MSG_IN_WINDOW, dlg->msg_show_window_w);
-	READ_SPIN_PREFS(PREFS_GUI_MSG_MAX_WINDOWS, dlg->msg_max_w);
-
-	/* Misc */
-	READ_TOGGLE_PREFS(PREFS_GUI_KEEP_SIZE, dlg->keep_window_size_w);
-	READ_TOGGLE_PREFS(PREFS_PREFS_AUTO_SAVE, dlg->save_on_exit_w);
-	READ_ENTRY_PREFS(PREFS_NET_MOTD, dlg->motd_w);
-	READ_ENTRY_PREFS(PREFS_NET_MOTD_WHEN_AWAY, dlg->motd_away_w);
-
-	/* change the apply button, to notify that the the dialog is now in sync with config
-	 * (however the config was not saved)
-	 */
-	set_config_dlg_modified(dlg, FALSE);
-
-	/* enable scattering of dialog */
-	dlg->gathering = FALSE;
-}
-
-/**
- * syncs dialog with the current configuration values
- */
-static void
-sync_dlg_from_config(struct config_dlg * dlg)
-{
-#define SET_SPIN_FROM_PREF(o, p) \
-	gtk_spin_button_set_value(GTK_SPIN_BUTTON(o), prefs_int(p))
-#define SET_TOGGLE_FROM_PREF(o, p) \
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o), prefs_bool(p))
-#define SET_OPTION_FROM_PREF(o, p) \
-	gtk_option_menu_set_history(GTK_OPTION_MENU(o), prefs_int(p))
-#define SET_ENTRY_FROM_PREF(o, p) \
-	gtk_entry_set_text(GTK_ENTRY(o), prefs_str(p))
-#define SET_IPV4_ENTRY_FROM_PREF(e, p) \
-	set_ipv4_entry((e), prefs_int(p))
-
-	/* Idle */
-	SET_TOGGLE_FROM_PREF(dlg->idle_enable_w, PREFS_IDLE_ENABLE);
- 	SET_SPIN_FROM_PREF(dlg->auto_away_w, PREFS_IDLE_AUTO_AWAY);
-	SET_SPIN_FROM_PREF(dlg->auto_offline_w, PREFS_IDLE_AUTO_OFFLINE);
-	
-	/* Pages */
-	SET_TOGGLE_FROM_PREF(dlg->pages_show_topic_entry, PREFS_GUI_TOPIC_BAR);
-	SET_TOGGLE_FROM_PREF(dlg->pages_present_on_private, PREFS_GUI_PRESENT_ON_PRIVATE);
-	SET_TOGGLE_FROM_PREF(dlg->pages_log_current_w, PREFS_MAIN_LOG_GLOBAL);
-	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_join_leave_w, PREFS_SESS_SUPPRESS_JOIN_LEAVE_TEXT);
-	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_rename_w, PREFS_SESS_SUPPRESS_RENAME_TEXT);
-	SET_TOGGLE_FROM_PREF(dlg->pages_suppress_mode_change_w, PREFS_SESS_SUPPRESS_MODE_TEXT);
-	SET_TOGGLE_FROM_PREF(dlg->date_channel_w, PREFS_SESS_STAMP_CHANNEL);
-	SET_TOGGLE_FROM_PREF(dlg->date_private_w, PREFS_SESS_STAMP_PRIVATE);
-	SET_TOGGLE_FROM_PREF(dlg->date_status_w, PREFS_SESS_STAMP_STATUS);
-	SET_OPTION_FROM_PREF(dlg->pages_notebook_pos_w, PREFS_GUI_PAGE_TAB_POS);
-
-	/* Misc */
-	SET_TOGGLE_FROM_PREF(dlg->keep_window_size_w, PREFS_GUI_KEEP_SIZE);
-	SET_TOGGLE_FROM_PREF(dlg->save_on_exit_w, PREFS_PREFS_AUTO_SAVE);
-	SET_ENTRY_FROM_PREF(dlg->motd_w, PREFS_NET_MOTD);
-	SET_ENTRY_FROM_PREF(dlg->motd_away_w, PREFS_NET_MOTD_WHEN_AWAY);
-
-	/* Tray icon */
-	SET_TOGGLE_FROM_PREF(dlg->tray_enable_w, PREFS_GUI_TRAY_ENABLE);
-	systray_pref_gui_tray_enable_toggled_cb(
-		GTK_TOGGLE_BUTTON(dlg->tray_enable_w), (gpointer)dlg);
-	SET_TOGGLE_FROM_PREF(dlg->tray_hide_on_startup_w, PREFS_GUI_TRAY_HIDE_WND_ON_STARTUP);
-	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_joinleave_w, PREFS_GUI_TRAY_TRIGGERS_JOIN_LEAVE);
-	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_channel_w, PREFS_GUI_TRAY_TRIGGERS_CHANNEL);
-	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_private_w, PREFS_GUI_TRAY_TRIGGERS_PRIVATE);
-	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_status_w, PREFS_GUI_TRAY_TRIGGERS_STATUS);
-	SET_TOGGLE_FROM_PREF(dlg->tray_trigger_topic_w, PREFS_GUI_TRAY_TRIGGERS_TOPIC);
-	SET_SPIN_FROM_PREF(dlg->tray_tooltip_lines_w, PREFS_GUI_TRAY_TOOLTIP_LINE_NUM);
-
-	/* Network */
-	SET_OPTION_FROM_PREF(dlg->net_type_w, PREFS_NET_TYPE);
-	SET_SPIN_FROM_PREF(dlg->net_port_w, PREFS_NET_PORT);
-	SET_ENTRY_FROM_PREF(dlg->net_charset_w, PREFS_NET_ENCODING);
-	SET_TOGGLE_FROM_PREF(dlg->net_reply_w, PREFS_NET_REPLY_INFO_REQ);
-	SET_TOGGLE_FROM_PREF(dlg->net_log_w, PREFS_NET_VERBOSE);
-	SET_TOGGLE_FROM_PREF(dlg->net_channel_greet_w, PREFS_NET_CHANNEL_NOTIFY);
-	SET_TOGGLE_FROM_PREF(dlg->net_use_multicast_w, PREFS_NET_USE_MULTICAST);
-	SET_IPV4_ENTRY_FROM_PREF(dlg->net_broadcast_w, PREFS_NET_BROADCAST_MASK);
-	SET_IPV4_ENTRY_FROM_PREF(dlg->net_multicast_w, PREFS_NET_MULTICAST_ADDR);
-
-	/* User list settings */
-	SET_TOGGLE_FROM_PREF(dlg->userlist_keep_unreplied_users_w, PREFS_USER_KEEP_UNREPLIED);
-	SET_SPIN_FROM_PREF(dlg->userlist_refresh_w, PREFS_USER_LIST_REFRESH);
-
-	/* Message settings */
-	SET_TOGGLE_FROM_PREF(dlg->msg_ignore_mass_w, PREFS_NET_IGNORE_MASS_MSG);
-	SET_TOGGLE_FROM_PREF(dlg->msg_ctrl_return_w, PREFS_GUI_MSG_CTRL_ENTER);
-	SET_TOGGLE_FROM_PREF(
-		dlg->msg_show_messages_in_offline_dnd_w, PREFS_GUI_MSG_SHOW_IN_OFFLINE_DND);
-	SET_TOGGLE_FROM_PREF(dlg->msg_show_window_w, PREFS_GUI_MSG_IN_WINDOW);
-	SET_SPIN_FROM_PREF(dlg->msg_max_w, PREFS_GUI_MSG_MAX_WINDOWS);
-	messages_pref_in_window_toggled_cb(
-		GTK_TOGGLE_BUTTON(dlg->msg_show_window_w), (gpointer)dlg);
-	
-	/* these settings are 'current' - disable the `Save' button */
-	set_config_dlg_modified(dlg, FALSE);
-}
-
-static void
-config_dlg_prefs_tree_selection_changed_cb(
-	GtkTreeSelection * selection, struct config_dlg * dlg)
-{
-	GtkTreeIter iter;
-	GtkTreeModel * model;
-	gint index;
-
-	if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
-		gtk_tree_model_get(model, &iter, CONFIG_TREE_INDEX, &index, -1);
-
-		if(index >= 0)
-			gtk_notebook_set_current_page(GTK_NOTEBOOK(dlg->notebook_w), index);
-	}
-}
-
-static void 
-show_config_dlg(struct config_dlg ** pdlg)
-{
-	struct config_dlg * dlg;
-	GtkWidget * hbox, * scrolled;
-	GtkCellRenderer * cell;
-	GtkTreeViewColumn * column;
-	GtkTreeSelection * selection;
-	GtkTreeIter iter;
-
-	if(*pdlg) return;
-	
-	*pdlg = dlg = g_malloc(sizeof(struct config_dlg));
-
-	dlg->is_changed = FALSE;
-	dlg->gathering = FALSE;
-
-	/* create config dlg and setup signals */
-	dlg->dlg_w = gtk_dialog_new_with_buttons(_("Preferences"), gui_get_main_window(), 0, NULL);
-
-	gtk_dialog_add_button(GTK_DIALOG(dlg->dlg_w), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
-	dlg->save_w = gtk_dialog_add_button(
-			GTK_DIALOG(dlg->dlg_w), GTK_STOCK_SAVE, GUI_RESPONSE_SAVE);
-	gtk_button_box_set_child_secondary(
-			GTK_BUTTON_BOX(GTK_DIALOG(dlg->dlg_w)->action_area), dlg->save_w, TRUE);
-	dlg->apply_w = gtk_dialog_add_button(
-			GTK_DIALOG(dlg->dlg_w), GTK_STOCK_APPLY, GTK_RESPONSE_APPLY);
-	gtk_dialog_add_button(GTK_DIALOG(dlg->dlg_w), GTK_STOCK_OK, GTK_RESPONSE_OK);
-
-	g_signal_connect(G_OBJECT(dlg->dlg_w), "response",
-		G_CALLBACK(config_dlg_response_handler), (gpointer)dlg);
-	g_signal_connect(G_OBJECT(dlg->dlg_w), "delete-event",
-		G_CALLBACK(gtk_true), NULL);
-	g_signal_connect(G_OBJECT(dlg->dlg_w), "key-press-event",
-		G_CALLBACK(config_dlg_key_cb), (gpointer)dlg);
-
-	/* make hbox for a tree and the notebook */
-	hbox = gtk_hbox_new(FALSE, 2);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg->dlg_w)->vbox), hbox, TRUE, TRUE, 0);
-
-	/* setup prefs tree and insert into the dialog */
-	dlg->prefs_tree_store = gtk_tree_store_new(CONFIG_TREE_NUM, G_TYPE_STRING, G_TYPE_INT);
-
-	dlg->prefs_tree_w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dlg->prefs_tree_store));
-	gtk_widget_set_size_request(dlg->prefs_tree_w, 150, -1);
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dlg->prefs_tree_w), FALSE);
-
-	/* add pref name renderer */
-	cell = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(
-			"Preference", cell,
-			"text", CONFIG_TREE_NAME, NULL);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(dlg->prefs_tree_w), column);
-
-	/* connect signals */
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dlg->prefs_tree_w));
-	g_signal_connect(
-		G_OBJECT(selection), "changed",
-		G_CALLBACK(config_dlg_prefs_tree_selection_changed_cb), dlg);
-
-	scrolled = gtk_scrolled_window_new(FALSE, FALSE);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(
-		GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-	gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
-	gtk_container_add(GTK_CONTAINER(scrolled), dlg->prefs_tree_w);
-
-	/* setup notebook and insert it into the dialog */
-	dlg->notebook_w = gtk_notebook_new();
-	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(dlg->notebook_w), FALSE);
-	gtk_notebook_set_show_border(GTK_NOTEBOOK(dlg->notebook_w), FALSE);
-	gtk_box_pack_start(GTK_BOX(hbox), dlg->notebook_w, TRUE, TRUE, 0);
-
-	gtk_widget_show_all(hbox);
-
-	/* add configuration pages */
-#define ADD_PAGE(name, frame) do { \
-		gint index = gtk_notebook_append_page( \
-			GTK_NOTEBOOK(dlg->notebook_w), (frame), NULL); \
-		gtk_tree_store_append(dlg->prefs_tree_store, &iter, NULL); \
-		gtk_tree_store_set( \
-			dlg->prefs_tree_store, &iter, \
-			CONFIG_TREE_NAME, (name), CONFIG_TREE_INDEX, index, -1); \
-	} while(0)
-
-	ADD_PAGE(_("Network settings"), make_net_frame(dlg));
-	ADD_PAGE(_("User list"), make_user_list_frame(dlg));
-	ADD_PAGE(_("Pages"), make_pages_frame(dlg));
-	ADD_PAGE(_("Messages"), make_messages_frame(dlg));
-	ADD_PAGE(_("Tray icon"), make_systray_frame(dlg));
-	ADD_PAGE(_("Idle"), make_idle_frame(dlg));
-	ADD_PAGE(_("Miscellaneous"), make_settings_frame(dlg));
-
-	/* show the window */
-	gtk_window_present(GTK_WINDOW(dlg->dlg_w));
-	gtk_widget_set_sensitive(dlg->save_w, !prefs_in_sync());
-}
-
-static void
-set_config_dlg_modified(struct config_dlg * dlg, gboolean is_changed)
-{
-	gtk_widget_set_sensitive(dlg->apply_w, is_changed);
-	if(is_changed)
-		gtk_widget_set_sensitive(dlg->save_w, is_changed);
-			
-	dlg->is_changed = is_changed;
-}
-
-static void
-destroy_config_dlg(struct config_dlg ** pdlg)
-{
-	if(*pdlg) {
-		g_object_unref((*pdlg)->prefs_tree_store);
-		gtk_widget_destroy((*pdlg)->dlg_w);
-
-		g_free(*pdlg);
-		*pdlg = NULL;
-	}
-}
-
-static void
-gui_config_event_cb(enum app_event_enum e, gpointer p, gint i)
-{
-	switch(e) {
-	case EVENT_MAIN_INIT:
-		the_dlg = NULL;
-		break;
-
-	case EVENT_MAIN_PRECLOSE:
-		destroy_config_dlg(&the_dlg);
-		break;
-		
-	case EVENT_PREFS_CHANGED:
-		/* update dialog, if not currently gathering */
-		if(the_dlg && !the_dlg->gathering)
-			sync_dlg_from_config(the_dlg);
-		break;
-
-	case EVENT_PREFS_SAVED:
-		/* disable 'Save' button, as the configuration now is in sync
-		 */
-		if(the_dlg)
-			gtk_widget_set_sensitive(the_dlg->save_w, FALSE);
-		break;
-	case EVENT_IFACE_SHOW_CONFIGURE_DLG:
-		/* make & show dialog */
-		show_config_dlg(&the_dlg);
-		sync_dlg_from_config(the_dlg);
-		break;
-	default:
-		break;	/* nothing */
-	}
-}
-
-/** exported routines
-  *****************************************/
-void gui_config_dlg_register()
-{
-	register_event_cb(
-		gui_config_event_cb,
-		EVENT_MAIN|EVENT_PREFS|EVENT_IFACE);
-}
-
diff -NrU2 vqcc-gtk-0.5/src/gui_msg.c vqcc-gtk-0.5.1-shaman5/src/gui_msg.c
--- vqcc-gtk-0.5/src/gui_msg.c	2005-01-06 13:16:08.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/gui_msg.c	2005-06-28 22:33:41.000000000 +0400
@@ -28,4 +28,9 @@
 #include <gdk/gdkkeysyms.h>
 
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
 #include "main.h"
 #include "gui.h"
@@ -37,4 +42,5 @@
 #include "sess.h"
 
+
 #define HAVE_EXPANDER_WIDGET \
 	((GTK_MAJOR_VERSION > 2) || ((GTK_MAJOR_VERSION==2) && (GTK_MINOR_VERSION>=4)))
@@ -50,7 +56,11 @@
 	GtkWidget	* window_w;
 	GtkWidget	* text_w;
+	GtkWidget 	* userlist;
+	GtkListStore * ulist_model;
 	GtkWidget	* send_w, * reply_w, * quote_w;
+	
 #if(HAVE_EXPANDER_WIDGET)
 	GtkWidget	* option_expander_w,
+				* option_user_expander_w,
 			* option_save_size_w, * option_ctrl_enter_w;
 #endif
@@ -60,4 +70,6 @@
 #define PMESSAGE_INFO(p) ((struct message_info*)p)
 
+
+
 /** static variables
   *****************************************/
@@ -68,4 +80,24 @@
   ***************************************/
 
+/*Set window manager "Urgent" hint*/
+static void
+handle_urgent(struct message_info * mi, gboolean add)
+{
+        XWMHints *hints;
+        GtkWidget *gtkwin = GTK_WINDOW(mi->window_w);
+
+        g_return_if_fail(gtkwin != NULL);
+        g_return_if_fail(gtkwin->window != NULL);
+
+        hints = XGetWMHints(GDK_WINDOW_XDISPLAY(gtkwin->window), GDK_WINDOW_XWINDOW(gtkwin->window));
+        if (add)
+                hints->flags |= XUrgencyHint;
+        else
+                hints->flags &= ~XUrgencyHint;
+        XSetWMHints(GDK_WINDOW_XDISPLAY(gtkwin->window),
+                    GDK_WINDOW_XWINDOW(gtkwin->window), hints);
+        XFree(hints);
+}
+
 /* message_init:
  *	initializes message list
@@ -86,6 +118,7 @@
 {
 	g_assert(mi && mi->remote_user_name);
-
+	
 	if(destroy_widget) {
+		gui_ulist_free((GtkListStore *)mi->ulist_model);
 		g_assert(mi->window_w);
 		gtk_widget_destroy(mi->window_w);
@@ -94,5 +127,5 @@
 	g_free(mi->remote_user_name);
 	g_free(mi);
-
+	
 	/* remove message struct from the list */
 	msg_list = g_list_remove(msg_list, mi);
@@ -127,34 +160,72 @@
 		orig = g_utf8_next_char(orig);
 	}
-
-	if(*prev_c != '\n') {
+	/*Now answer text will be at top of message*/
+	/*if(*prev_c != '\n') {
 		g_string_append_c(quoted, '\n');
-	}
-
+	}*/
+	
+	g_string_prepend_c(quoted, '\n');
 	return quoted;
 }
 
+
+/*moved to util.h
+enum user_list_column_enum {
+	COLUMN_ICON,
+	COLUMN_NICKNAME,
+	COLUMN_USER_PTR,
+	
+	COLUMN_NUM
+};
+*/
+
+
 static void
 message_send(struct message_info * mi)
 {
 	GtkTextIter si, ei;
-	gpointer event_v[2];
+	gpointer event_v[3];
+	GtkTreeIter i;
+	//gpointer iter_user;
+	GValue v = {0,};
+	GValue sel = {0,};
 
-	if(mi->remote_user_id) {
+	if(mi->remote_user_id!=NULL){
 		/* "send" */
 		gtk_text_buffer_get_start_iter(mi->buffer, &si);
 		gtk_text_buffer_get_end_iter(mi->buffer, &ei);
-
-		/* send net message to the user */
-		EVENT_V(event_v,0) = mi->remote_user_id;
-		EVENT_V(event_v,1) = gtk_text_buffer_get_text(mi->buffer, &si, &ei, TRUE);
-		raise_event(EVENT_MESSAGE_SEND, event_v, 0);
-		g_free(EVENT_V(event_v,1));
-
+		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mi->ulist_model), &i)) {
+			do {
+				gtk_tree_model_get_value(GTK_TREE_MODEL(mi->ulist_model), &i,
+					COLUMN_SELECTED, &sel);
+				gtk_tree_model_get_value(GTK_TREE_MODEL(mi->ulist_model), &i,
+					COLUMN_USER_PTR, &v);
+
+				if(g_value_get_boolean(&sel)&&(g_value_get_pointer(&v)!=NULL)){
+				/* send net message to the user */
+
+					EVENT_V(event_v,0) =  g_value_get_pointer(&v);
+					EVENT_V(event_v,1) = gtk_text_buffer_get_text(mi->buffer, &si, &ei, TRUE);
+		
+					if ((mi->my==TRUE) && (mi->mass_message==TRUE))
+						EVENT_V(event_v,2) = TRUE;
+					else
+						EVENT_V(event_v,2) = FALSE;
+		
+					raise_event(EVENT_MESSAGE_SEND, event_v, 0);
+					g_free(EVENT_V(event_v,1));
+				}
+				g_value_unset(&v);
+				g_value_unset(&sel);
+		
+			} while((gtk_tree_model_iter_next(GTK_TREE_MODEL(mi->ulist_model), &i)));
+		}
+	}
 		/* delete this message */
 		message_delete(mi, TRUE);
-	}
 }
 
+
+
 /* message_turn_into_my:
  *	changes the message so the user can
@@ -187,5 +258,10 @@
 	if(quoted)
 		g_string_free(quoted, TRUE);
-
+	
+	gtk_text_buffer_get_start_iter(mi->buffer, &start);
+	gtk_text_buffer_place_cursor(mi->buffer,&start);
+	
+	
+	
 	/* hide reply/quote buttons and emerge send one */
 	gtk_widget_hide(mi->reply_w);
@@ -230,4 +306,16 @@
 }
 
+
+/*Unset window manager "Urgent" hint */
+static gboolean
+message_cb_focus_change_event(
+	GtkWidget * widget, GdkEventFocus * focus_event, struct message_info * mi)
+{
+	gboolean focus_state = focus_event->in!=0;
+	if(focus_state)
+		handle_urgent(mi,FALSE);	
+	return FALSE;
+}
+
 /* message_cb_delete_event:
  *	gets notified if the user tries to close the message dialog
@@ -343,4 +431,7 @@
 }
 
+
+
+
 /* message_make_window:
  *	build up and show GTK+ dialog for the message specified (mi)
@@ -349,8 +440,10 @@
 message_make_window(struct message_info * mi, const gchar * preset_text)
 {
-	GtkWidget * b, * w, * option_vbox;
+	GtkWidget * b, * main_box, * w, * option_vbox;
 	gchar * title;
 	gint dlg_width, dlg_height;
-
+	gboolean HaveFocus;
+	GList * l;
+	
 	g_assert(mi && mi->remote_user_id && mi->remote_user_name);
 
@@ -366,4 +459,5 @@
 #endif
 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+	gtk_window_set_type_hint(GTK_WINDOW(mi->window_w),GDK_WINDOW_TYPE_HINT_NORMAL);	
 	g_free(title);
 	gui_misc_set_icon_for(GTK_WINDOW(mi->window_w));
@@ -373,4 +467,6 @@
 	}
 
+
+	
 	/* add send/quote/reply buttons */
 	mi->quote_w = gtk_dialog_add_button(
@@ -394,7 +490,21 @@
 		G_OBJECT(mi->window_w), "response",
 		G_CALLBACK(message_cb_response), (gpointer)mi);	
-
+	g_signal_connect(G_OBJECT(mi->window_w), "focus-in-event",
+		G_CALLBACK(message_cb_focus_change_event), (gpointer)mi);
+		
+		
+		
+	/* create horizontal paned */
+	main_box = gtk_hpaned_new();
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(mi->window_w)->vbox), main_box, TRUE, TRUE, 0);
+	
+	/*if my massmessage then show user list*/
+	if(mi->my && mi->mass_message)
+		gtk_paned_set_position((GtkPaned *) main_box,dlg_width-200);
+	else
+		gtk_paned_set_position((GtkPaned *) main_box,dlg_width);
+	
 	b = gtk_vbox_new(FALSE, 2);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(mi->window_w)->vbox), b);
+	gtk_container_add(GTK_CONTAINER(main_box), b);
 
 	w = gtk_scrolled_window_new(NULL, NULL);
@@ -442,8 +552,16 @@
 #endif
 
+	/*Add user list*/
+	mi->ulist_model=(GtkListStore *)gui_ulist_create_model(TRUE);
+	mi->userlist=(GtkWidget *)gui_ulist_create(mi->ulist_model,TRUE,((mi->my &&
+							mi->mass_message)? NULL : mi->remote_user_id ));
+	gtk_container_add(GTK_CONTAINER(main_box), mi->userlist);
+	
+	
 	/*
 	 * Disable `Send' button so the user cant send message if the receiver
 	 * cannot or will refuse to receive the message.
 	 */
+	if(mi->my) 
 	gtk_widget_set_sensitive(
 		mi->send_w,
@@ -464,5 +582,35 @@
 		gtk_widget_hide(mi->send_w);
 	}
+	
+	/*test have any editable window focus?*/
+	HaveFocus=FALSE;
+	struct message_info * mi_tmp;
+	for(l = msg_list; l; l = l->next) {
+		mi_tmp=((struct message_info *)l->data);
+		if( GTK_WIDGET_HAS_FOCUS(mi_tmp->text_w)
+			&&gtk_text_view_get_editable(GTK_TEXT_VIEW(mi_tmp->text_w)) ){
+			HaveFocus=TRUE;
+			break;
+		}
+	}
+	
+	if(
+		(  (!mi->my)&&(prefs_bool(PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES)||
+		(HaveFocus))&&(!mi->mass_message)  )
+		||(  (!mi->my)&&prefs_bool(PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES)
+		&&(mi->mass_message)  )
+		)
+			gtk_window_iconify(GTK_WINDOW(mi->window_w));			
+			
+		
+	
 	gtk_window_present(GTK_WINDOW(mi->window_w));
+	
+	if(
+		(  (!mi->my)&&(prefs_bool(PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES)||
+		(HaveFocus))&&(!mi->mass_message)  )
+		||(  (!mi->my)&&prefs_bool(PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES)
+		&&(mi->mass_message)  )
+		)	handle_urgent(mi,TRUE);
 }
 
@@ -496,8 +644,12 @@
 	/* make and show up message window */
 	message_make_window(mi, text);
-
+	
+	//if (my)
+	//	gtk_window_present(GTK_DIALOG(mi->window_w));
 	return mi;
 }
 
+
+
 /* message_cleanup:
  *	deletes all the messages and all the allocated
@@ -672,4 +824,8 @@
 		prefs_register(PREFS_GUI_MSG_MAX_WINDOWS, PREFS_TYPE_UINT,
 			_("Maximum message windows"), NULL, NULL);
+		prefs_register(PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES, PREFS_TYPE_BOOL,
+			_("Minimize received private messages"), NULL, NULL);
+		prefs_register(PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES, PREFS_TYPE_BOOL,
+			_("Minimize received mass messages"), NULL, NULL);
 		prefs_register(PREFS_GUI_MSG_CTRL_ENTER, PREFS_TYPE_BOOL,
 			_("CTRL-Enter sends message"), NULL, NULL);
@@ -705,4 +861,7 @@
 		message_new(v, TRUE, FALSE, NULL);
 		break;
+	case EVENT_IFACE_USER_MASS_MESSAGE_REQ:
+		message_new(v, TRUE, TRUE, NULL);
+		break;
 	case EVENT_NET_MSG_MESSAGE:
 		message_net_msg(
@@ -729,3 +888,2 @@
 		EVENT_MAIN|EVENT_IFACE|EVENT_USER|EVENT_NET);
 }
-
diff -NrU2 vqcc-gtk-0.5/src/gui_msg.h vqcc-gtk-0.5.1-shaman5/src/gui_msg.h
--- vqcc-gtk-0.5/src/gui_msg.h	2005-01-06 13:16:09.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/gui_msg.h	2005-04-13 17:38:06.000000000 +0400
@@ -25,4 +25,6 @@
 /* preferences registered in the `gui_msg' module */
 #define PREFS_GUI_MSG_IN_WINDOW		"gui/msg/in_window"
+#define PREFS_GUI_MSG_MINIMIZE_PRIVATE_MESSAGES		"gui/msg/minimize_private_messages"
+#define PREFS_GUI_MSG_MINIMIZE_MASS_MESSAGES		"gui/msg/minimize_mass_messages"
 #define PREFS_GUI_MSG_SUGGESTED_SIZE	"gui/msg/suggested_size"
 #define PREFS_GUI_MSG_MAX_WINDOWS	"gui/msg/max_windows"
@@ -33,3 +35,2 @@
 
 #endif /* #ifndef GUI_MSG_H__ */
-
diff -NrU2 vqcc-gtk-0.5/src/gui_ulist.c vqcc-gtk-0.5.1-shaman5/src/gui_ulist.c
--- vqcc-gtk-0.5/src/gui_ulist.c	2004-12-23 22:40:00.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/gui_ulist.c	2005-06-27 21:05:59.000000000 +0400
@@ -50,14 +50,5 @@
 #define ULIST_ACTIVE(user)	(user ? user_is_active(user): gui_is_active())
 
-enum user_list_column_enum {
-	COLUMN_ICON,
-	COLUMN_NICKNAME,
-	COLUMN_USER_PTR,
-	COLUMN_NUM
-};
 
-/** static vars
-  **********************************************/
-static GtkListStore	* ulist_model;
 
 /* user info tip */
@@ -72,4 +63,10 @@
 static GdkPoint		info_tip_pos;
 
+/** static vars
+  **********************************************/
+//static GtkListStore	* ulist_model;
+static GList * ulist_model_list;
+static int ulist_model_count;
+
 /** static routines
   **********************************************/
@@ -92,4 +89,13 @@
 
 static void
+user_menu_mass_send_cb(GtkMenuItem * item, GtkMenuShell * menu)
+{
+	gpointer user = user_by_name(g_object_get_data(G_OBJECT(menu), "username"));
+	if(user!=NULL)
+	raise_event(EVENT_IFACE_USER_MASS_MESSAGE_REQ, user, 0);
+}
+
+
+static void
 user_menu_beep_cb(GtkMenuItem * item, GtkMenuShell * menu)
 {
@@ -165,4 +171,10 @@
 	gtk_menu_shell_append(menu, item_w);
 
+	/* "Send mass message" */
+	item_w = util_image_menu_item(
+		GUI_STOCK_SEND_MESSAGE, _("<b>Send mass message</b>"),
+		G_CALLBACK(user_menu_mass_send_cb), menu);
+	gtk_menu_shell_append(menu, item_w);	
+	
 	/* "Beep" */
 	item_w = util_image_menu_item(NULL, _("Beep"), G_CALLBACK(user_menu_beep_cb), menu);
@@ -415,4 +427,22 @@
 }
 
+/*Toggle user*/
+static void
+check_user_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
+{
+	GtkTreeIter iter;
+	gboolean check_user;
+
+		gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(data), &iter, path_str);
+		gtk_tree_model_get((GtkListStore *)GTK_TREE_MODEL(data), &iter,
+					   COLUMN_SELECTED, &check_user,
+					   -1);
+	
+		gtk_list_store_set((GtkListStore *)GTK_TREE_MODEL(data), &iter,
+					   COLUMN_SELECTED, !check_user,
+					   -1);
+}
+
+
 /* info_tip_set_content_for_me
  *	create info tip content for ourselves
@@ -471,7 +501,13 @@
 	time_t last_time_active;
 
+	
+	/* add user ip */
+	escaped = g_markup_escape_text( inet_ntoa( htonl(user_ip_of(user_id)) ), -1);
+	g_string_printf(markup, "<b><u>ip: %s</u></b>", escaped);
+	g_free(escaped);
+
 	/* add user name */
 	escaped = g_markup_escape_text(user_name_of(user_id), -1);
-	g_string_printf(markup, "<big><b><u>%s</u></b></big>", escaped);
+	g_string_append_printf(markup, "\n<big><b><u>%s</u></b></big>", escaped);
 	g_free(escaped);
 
@@ -543,7 +579,12 @@
 	gchar * escaped;
 
+	/* add user ip */
+	escaped = g_markup_escape_text( inet_ntoa( htonl(user_ip_of(user_id)) ), -1);
+	g_string_printf(markup, "<b><u>ip: %s</u></b>", escaped);
+	g_free(escaped);
+	
 	/* add user name */
 	escaped = g_markup_escape_text(user_name_of(user_id), -1);
-	g_string_printf(markup, "<big><b><u>%s</u></b></big>", escaped);
+	g_string_append_printf(markup, "\n<big><b><u>%s</u></b></big>", escaped);
 	g_free(escaped);
 
@@ -719,7 +760,10 @@
 		if(cell_found) {
 			/* get user of the focused cell */
-			gtk_tree_model_get_iter(GTK_TREE_MODEL(ulist_model), &cell_iter, cell_path);
+			GtkListStore	* model;
+			model = gtk_tree_view_get_model(treeview_w);
+			gtk_tree_model_get_iter((GtkTreeModel *)GTK_TREE_MODEL(model),
+				(GtkTreeIter *) &cell_iter,(GtkTreePath *) cell_path);
 			gtk_tree_model_get(
-				GTK_TREE_MODEL(ulist_model), &cell_iter,
+				GTK_TREE_MODEL(model), &cell_iter,
 				COLUMN_USER_PTR, &info_tip_user, -1);
 
@@ -763,5 +807,6 @@
 	const char * user_name,
 	enum user_mode_enum mode,
-	GtkTreeIter * where)
+	GtkTreeIter * where,
+	GtkListStore * ulist_model)
 {
 	gboolean valid;
@@ -795,6 +840,12 @@
 {
 	GtkTreeIter iter;
+	GList * l;
+	GtkListStore * ulist_model;
+
 
-	ulist_where_to_insert(ULIST_NAME(user), ULIST_MODE(user), &iter);
+	for(l = ulist_model_list; l; l = l->next) {
+	ulist_model = ((GtkListStore *)l->data);
+		
+	ulist_where_to_insert(ULIST_NAME(user), ULIST_MODE(user), &iter, ulist_model);
 	gtk_list_store_set(
 		ulist_model, &iter,
@@ -803,12 +854,11 @@
 		COLUMN_USER_PTR, user,
 		-1);
+	}//for
 }
 
 static gboolean
-ulist_iter_by_user(gpointer user, GtkTreeIter * iter)
+ulist_iter_by_user(gpointer user, GtkTreeIter * iter,GtkListStore * ulist_model)
 {
 	gpointer iter_user;
-
-	g_assert(iter);
 	
 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ulist_model), iter)) {
@@ -827,7 +877,14 @@
 {
 	GtkTreeIter iter;
+	GList * l;
+	GtkListStore * ulist_model;
 
-	if(ulist_iter_by_user(user, &iter))
+
+	for(l = ulist_model_list; l; l = l->next) {
+	ulist_model = ((GtkListStore *)l->data);
+		
+	if(ulist_iter_by_user(user, &iter, ulist_model))
 		gtk_list_store_remove(ulist_model, &iter);
+	}//for
 }
 
@@ -836,6 +893,12 @@
 {
 	GtkTreeIter iter;
+	GList * l;
+	GtkListStore * ulist_model;
 
-	if(ulist_iter_by_user(user, &iter)) {
+
+	for(l = ulist_model_list; l; l = l->next) {
+	ulist_model = ((GtkListStore *)l->data);
+		
+	if(ulist_iter_by_user(user, &iter, ulist_model)) {
 		gtk_list_store_set(
 			ulist_model, &iter,
@@ -843,4 +906,5 @@
 		       	-1);
 	}
+	}//for
 }
 
@@ -915,14 +979,32 @@
  ******************************************/
 
+
+GtkListStore *
+gui_ulist_create_model(gboolean ismessage)
+{
+GtkListStore *ulist_model;
+	if(!ismessage)
+	ulist_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+	else
+	ulist_model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+return ulist_model;
+}
+
 /* gui_ulist_create:
  *	creates & setups new userlist widget
  *	and static variables
  */
+
+/*shaman this is wrong but i don't know how to write better*/
 GtkWidget *
-gui_ulist_create()
+gui_ulist_create(GtkListStore *ulist_model,gboolean ismessage,gpointer user_id)
 {
-	GtkWidget * treeview_w, * scrolled_w;
+	GtkWidget * treeview_w;//, * scrolled_w;
 	GtkCellRenderer * icon_renderer;
-	
+	GtkListStore * ulist_model_tmp;
+	GtkCellRenderer *renderer;
+	GtkWidget *scrolled_w;
+	info_tip_destroy();
+		
 	/* initialize misc variables
 	 */
@@ -934,6 +1016,11 @@
 
 	/* create list store */
+/*	if(!ismessage)
 	ulist_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+	else
+	ulist_model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+	*/
 	
+
 	/* create scrolled window & tree view widget */
 	scrolled_w = gtk_scrolled_window_new(NULL, NULL);
@@ -941,5 +1028,6 @@
 		GTK_SCROLLED_WINDOW(scrolled_w),
 		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
+	
+	
 	treeview_w = gtk_tree_view_new();
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview_w), FALSE);
@@ -960,4 +1048,44 @@
 		GTK_TREE_VIEW(treeview_w), -1, NULL,
 		gtk_cell_renderer_text_new(), "text", COLUMN_NICKNAME, NULL);
+		
+	if(ismessage){
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled",
+			 G_CALLBACK(check_user_cb), ulist_model);
+		
+	gtk_tree_view_insert_column_with_attributes(
+		GTK_TREE_VIEW(treeview_w), 0, NULL,
+		renderer, "active", COLUMN_SELECTED, NULL);
+		
+		ulist_model_tmp=(GtkListStore *)g_list_first(ulist_model_list)->data;
+		GValue v = {0,};
+		GtkTreeIter i,i2;
+		gboolean select_it;
+		
+		if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ulist_model_tmp), &i) ){
+			do{
+				gtk_tree_model_get_value(GTK_TREE_MODEL(ulist_model_tmp),
+					&i, COLUMN_USER_PTR, &v);
+				select_it=FALSE;
+				gtk_list_store_append (ulist_model, &i2);	
+				
+				if((user_id==NULL)||(user_id!=NULL && user_id==g_value_get_pointer(&v)))
+					select_it=TRUE;
+
+				gtk_list_store_set(
+					ulist_model, &i2,
+					COLUMN_ICON,
+					util_user_state_stock(ULIST_MODE(g_value_get_pointer(&v)),
+					ULIST_ACTIVE(g_value_get_pointer(&v))),
+					COLUMN_NICKNAME, ULIST_NAME(g_value_get_pointer(&v)),
+					COLUMN_USER_PTR, g_value_get_pointer(&v),
+					COLUMN_SELECTED,select_it,
+					-1);	
+					
+				g_value_unset(&v);
+			}while(gtk_tree_model_iter_next(GTK_TREE_MODEL(ulist_model_tmp), &i));
+		}//if
+		
+	}else{
 
 	/* connect signals */
@@ -972,6 +1100,16 @@
 	g_signal_connect(G_OBJECT(treeview_w),
 			"popup-menu", G_CALLBACK(ulist_popup_menu_cb), NULL);
+	}
+	
+//	if(ismessage){
+//	}//if ismessage
+	
+	/* add new model to the list */
+	ulist_model_list = g_list_prepend(ulist_model_list, ulist_model);
+	++ulist_model_count;
 
+//ulist_model=NULL;
 	return scrolled_w;
+	//return MyUlist;
 }
 
@@ -979,6 +1117,8 @@
  *	frees any static data unreferenced in GtkWidget
  */
-void gui_ulist_free()
+void gui_ulist_free(GtkListStore * ulist_model)
 {
+	ulist_model_list = g_list_remove(ulist_model_list, ulist_model);
+	--ulist_model_count;
 }
 
@@ -988,7 +1128,9 @@
 void gui_ulist_register()
 {
+	ulist_model_list = NULL;
+	ulist_model_count = 0;
+	
 	register_event_cb(
 		ulist_event_cb,
 		EVENT_MAIN | EVENT_USER | EVENT_NET | EVENT_IFACE);
 }
-
diff -NrU2 vqcc-gtk-0.5/src/gui_ulist.h vqcc-gtk-0.5.1-shaman5/src/gui_ulist.h
--- vqcc-gtk-0.5/src/gui_ulist.h	2004-09-21 16:37:48.000000000 +0400
+++ vqcc-gtk-0.5.1-shaman5/src/gui_ulist.h	2005-04-13 19:27:11.000000000 +0400
@@ -22,9 +22,9 @@
 #ifndef GUI_ULIST_H__
 #define GUI_ULIST_H__
-
+GtkListStore * gui_ulist_create_model();
 GtkWidget * gui_ulist_create();
 void gui_ulist_free();
 void gui_ulist_register();
+static GtkListStore * main_ulist_model;
 
 #endif /* #ifndef GUI_ULIST_H__ */
-
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/link.c vqcc-gtk-0.5.1-shaman5/src/libqcproto/link.c
--- vqcc-gtk-0.5/src/libqcproto/link.c	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/link.c	2005-06-28 19:03:00.000000000 +0400
@@ -284,9 +284,11 @@
 	const qcs_msg * msg )
 {
+	
 	char * datagram;
 	ssize_t datagram_len, datagram_sent;
 	struct sockaddr_in sab;
 	link_data * link = (link_data *)link_id;
-
+	
+	
 	// check link
 	if(!VALID_ID(link_id)) ERRRET(EINVAL);
@@ -296,4 +298,5 @@
 	switch(link->proto) {
 	case QCS_PROTO_VYPRESS:
+		
 		datagram = qcs__make_vypress_msg(msg, &datagram_len);
 		break;
@@ -305,19 +308,22 @@
 		break;
 	}
+	
 	if(datagram==NULL)
 		ERRRET(EINVAL);
-
 	sab.sin_family = PF_INET;
-	sab.sin_port = htons(link->port);
-	sab.sin_addr.s_addr = htonl(link->broadcast_addr);
+	sab.sin_port = htons(link->port); 
+	sab.sin_addr.s_addr =(msg->broadcast==1 || msg->src_ip==0)? htonl(link->broadcast_addr): htonl(msg->src_ip);
 	datagram_sent = sendto(
 		link->tx, datagram, datagram_len, 0,
 		(struct sockaddr*)&sab, sizeof(sab));
 
-	free(datagram);
+	
 
-	if(datagram_sent != datagram_len)
+	if(datagram_sent != datagram_len){
+		printf("net error to ip: %d  %d    %s           %s\n ",msg->broadcast ,msg->src_ip , inet_ntoa( htonl(msg->src_ip)  ) , datagram);
+		free(datagram);
 		ERRRET(ENETUNREACH);
-
+	}
+	free(datagram);
 	return 1;
 }
@@ -391,4 +397,6 @@
 	msg->umode = QCS_UMODE_INVALID;
 	msg->uactive = 1;
+	msg->broadcast = 0;
+	msg->src_ip=0;
 	msg->src = msg->dst = msg->text = msg->supp = msg->chan = NULL;
 
@@ -399,5 +407,5 @@
 {
 	if(msg==NULL) return;
-
+	
 	if( msg->src ) free( msg->src );
 	if( msg->dst ) free( msg->dst );
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/p_qchat.c vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_qchat.c
--- vqcc-gtk-0.5/src/libqcproto/p_qchat.c	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_qchat.c	2005-06-28 19:48:06.000000000 +0400
@@ -47,5 +47,5 @@
 char *
 qcs__make_qchat_msg(
-	const qcs_msg * msg,
+	qcs_msg * msg,
 	ssize_t * pmsg_len )
 {
@@ -66,4 +66,5 @@
 		ADDCHAR('0');
 		ADDSTR(msg->src);
+		msg->broadcast = 1;
 		break;
 	case QCS_MSG_REFRESH_ACK:
@@ -80,4 +81,5 @@
 		ADDSTR(msg->src);
 		ADDSTR(msg->text);
+	    msg->broadcast=1;
 		break;
 	case QCS_MSG_CHANNEL_JOIN:
@@ -87,4 +89,5 @@
 		ADDCHAR(qcs__net_qcumode(msg->umode));
 		ADDCHAR('0');		/* unknown purpose !! */
+	    msg->broadcast=1;
 		break;
 	case QCS_MSG_CHANNEL_LEAVE:
@@ -93,4 +96,5 @@
 		ADDCHAN(msg->chan);
 		ADDCHAR('0');		/* unknown */
+	    msg->broadcast=1;
 		break;
 	case QCS_MSG_CHANNEL_ME:
@@ -99,4 +103,5 @@
 		ADDSTR(msg->src);
 		ADDSTR(msg->text);
+		msg->broadcast=1;
 		break;
 	case QCS_MSG_MESSAGE_ACK:
@@ -125,4 +130,5 @@
 		ADDSTR(msg->text);
 		ADDCHAR('0');		/* unknown */
+		msg->broadcast=1;
 		break;
 	case QCS_MSG_MODE_CHANGE:
@@ -131,4 +137,5 @@
 		ADDCHAR(qcs__net_qcumode(msg->umode));
 		ADDCHAR('0');		/* unknown */
+		msg->broadcast=1;
 		break;
 	case QCS_MSG_ACTIVE_CHANGE:
@@ -136,4 +143,5 @@
 		ADDSTR(msg->src);
 		ADDCHAR(qcs__net_qcuactive(msg->uactive));
+		msg->broadcast=1;
 		break;
 	case QCS_MSG_TOPIC_REPLY:
@@ -160,4 +168,5 @@
 		ADDCHAR('B');
 		ADDSTR(msg->text);
+		msg->broadcast=1;
 		break;
 	case QCS_MSG_INFO_REPLY:
@@ -260,5 +269,4 @@
 {
 	char ch;
-
 	assert( pmsg && pmsg_len && msg );
 
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/p_qchat.h vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_qchat.h
--- vqcc-gtk-0.5/src/libqcproto/p_qchat.h	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_qchat.h	2005-06-27 18:16:44.000000000 +0400
@@ -28,5 +28,5 @@
 #define P_QCHAT_H
 
-char * qcs__make_qchat_msg(const qcs_msg *, ssize_t *);
+char * qcs__make_qchat_msg(qcs_msg *, ssize_t *);
 int qcs__parse_qchat_msg(const char *, ssize_t, qcs_msg *);
 
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/p_vypress.c vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_vypress.c
--- vqcc-gtk-0.5/src/libqcproto/p_vypress.c	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_vypress.c	2005-06-27 18:19:34.000000000 +0400
@@ -46,5 +46,5 @@
 
 char * qcs__make_vypress_msg(
-	const qcs_msg * msg,
+	qcs_msg * msg,
 	ssize_t * pmsg_len )
 {
@@ -64,4 +64,5 @@
 		ADDCHAN(msg->chan);
 		ADDSTR(msg->text);
+		msg->broadcast=1;
 		break;
 		
@@ -89,5 +90,5 @@
 		break;
 	}
-
+	
 	/* allocate buffer for final version */
 	msg_buf = malloc(QCP_MAXUDPSIZE+10);
@@ -97,8 +98,9 @@
 		return NULL;
 	}
-
+	
+	
 	/* append msg id and register for duplicates */
 	qcs__generate_signature( msg_buf );
-
+	
 	/* build up final "version" */
 	memcpy(msg_buf+10, raw_msg, raw_len);
@@ -106,5 +108,5 @@
 		*pmsg_len = raw_len + 10;
 	}
-
+	
 	free(raw_msg);
 
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/p_vypress.h vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_vypress.h
--- vqcc-gtk-0.5/src/libqcproto/p_vypress.h	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/p_vypress.h	2005-06-27 18:19:43.000000000 +0400
@@ -28,5 +28,5 @@
 #define P_VYPRESS_H
 
-char * qcs__make_vypress_msg(const qcs_msg *, ssize_t *);
+char * qcs__make_vypress_msg(qcs_msg *, ssize_t *);
 int qcs__parse_vypress_msg(const char *, ssize_t, qcs_msg *);
 
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/qcproto.h vqcc-gtk-0.5.1-shaman5/src/libqcproto/qcproto.h
--- vqcc-gtk-0.5/src/libqcproto/qcproto.h	2004-12-17 05:04:29.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/qcproto.h	2005-06-27 18:17:27.000000000 +0400
@@ -232,4 +232,5 @@
 };
 
+	
 /* qcs_msg:
  *	protocol message type */
@@ -239,4 +240,5 @@
 	unsigned long src_ip;	/* IP address of message source */
 	int uactive;		/* used to notify if the user is active */
+	int broadcast; 		/*  */
 	char * src;	/* src nickname */
 	char * dst;	/* dst nickname */
diff -NrU2 vqcc-gtk-0.5/src/libqcproto/supp.c vqcc-gtk-0.5.1-shaman5/src/libqcproto/supp.c
--- vqcc-gtk-0.5/src/libqcproto/supp.c	2004-12-22 20:51:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/libqcproto/supp.c	2005-04-12 13:19:53.000000000 +0400
@@ -214,4 +214,2 @@
 	return 1;
 }
-
-
diff -NrU2 vqcc-gtk-0.5/src/main.h vqcc-gtk-0.5.1-shaman5/src/main.h
--- vqcc-gtk-0.5/src/main.h	2005-01-03 04:20:22.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/main.h	2005-04-07 23:34:17.000000000 +0400
@@ -92,4 +92,5 @@
 	EVENT_IFACE_USER_INFO_REQ,	/* p = user_id */
 	EVENT_IFACE_USER_MESSAGE_REQ,
+	EVENT_IFACE_USER_MASS_MESSAGE_REQ,
 	EVENT_IFACE_USER_BEEP_REQ,
 	EVENT_IFACE_USER_OPEN_REQ,
@@ -170,4 +171,5 @@
 	EVENT_MESSAGE	= 0x08000,
 	EVENT_MESSAGE_SEND,		/* p={uid, text}		*/
+	EVENT_MASS_MESSAGE_SEND,/* p={ text}		*/
 
 	EVENT_IDLE	= 0x10000,
@@ -212,3 +214,2 @@
 
 #endif /* #ifndef MAIN_H__ */
-
diff -NrU2 vqcc-gtk-0.5/src/net.c vqcc-gtk-0.5.1-shaman5/src/net.c
--- vqcc-gtk-0.5/src/net.c	2005-01-06 13:16:09.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/net.c	2005-06-28 21:02:34.000000000 +0400
@@ -1,1149 +1,1171 @@
-/*
- * net.c: network routines
- * Copyright (C) 2002-2004 Saulius Menkevicius
- *
- * 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
- *
- * $Id: net.c,v 1.36 2005/01/06 10:16:09 bobas Exp $
- */
-
-#include <glib.h>
-#include <errno.h>
-#include <string.h>
-
-#include "libqcproto/qcproto.h"
-
-#include "main.h"
-#include "net.h"
-#include "prefs.h"
-#include "sess.h"
-#include "user.h"
-#include "gui.h"
-
-#define NET_DEFAULT_CHARSET "ISO-8859-1"
-
-/** static vars
-  *************************/
-static qcs_link net;
-static enum net_type_enum net_type;
-static guint net_event_source;
-static GString * old_nickname;
-
-#define LOG_NET		N_("Network")
-
-#define ERRSTR_ENCODING	N_("Charset encoding/decoding error; \
-please check \"Network charset\" under the \"Network\" on the Preferences dialog")
-
-/** local routines
-  *************************/
-static gboolean net_connect();
-static void net_disconnect();
-
-static enum user_mode_enum
-net_local_mode(int qcs_umode)
-{
-	enum user_mode_enum m;
-
-	switch(qcs_umode) {
-	case QCS_UMODE_NORMAL:	m = UMODE_NORMAL;	break;
-	case QCS_UMODE_OFFLINE:	m = UMODE_OFFLINE;	break;
-	case QCS_UMODE_DND:	m = UMODE_DND;		break;
-	case QCS_UMODE_AWAY:	m = UMODE_AWAY;		break;
-	case QCS_UMODE_INVALID:	m = UMODE_NULL;		break;
-	}
-	return m;
-}
-
-static int
-net_qcs_mode(enum user_mode_enum local_mode)
-{
-	int m;
-
-	switch(local_mode) {
-	case UMODE_NORMAL:
-	case UMODE_INVISIBLE:
-		m = QCS_UMODE_NORMAL;
-		break;
-	case UMODE_DND:		m = QCS_UMODE_DND;	break;
-	case UMODE_AWAY:	m = QCS_UMODE_AWAY;	break;
-	case UMODE_OFFLINE:	m = QCS_UMODE_OFFLINE;	break;
-	default:		m = QCS_UMODE_INVALID;	break;
-	}
-	return m;
-}
-
-static void
-delete_converted_msg(qcs_msg * m)
-{
-	if(m->src) g_free(m->src);
-	if(m->dst) g_free(m->dst);
-	if(m->text) g_free(m->text);
-	if(m->supp) g_free(m->supp);
-	if(m->chan) g_free(m->chan);
-	g_free(m);
-}
-
-static qcs_msg *
-convert_msg_charset(const qcs_msg * m, const gchar * to, const gchar * from)
-{
-	qcs_msg * t = g_new0(qcs_msg, 1);
-
-	t->msg = m->msg;
-	t->umode = m->umode;
-	t->uactive = m->uactive;
-	t->src_ip = m->src_ip;
-	t->src = !m->src ? NULL: g_convert_with_fallback(m->src, -1, to, from, "?", NULL, NULL, NULL);
-	t->dst = !m->dst ? NULL: g_convert_with_fallback(m->dst, -1, to, from, "?", NULL, NULL, NULL);
-	t->text = !m->text ? NULL: g_convert_with_fallback(m->text, -1, to, from, "?", NULL, NULL, NULL);
-	t->supp = !m->supp ? NULL: g_convert_with_fallback(m->supp, -1, to, from, "?", NULL, NULL, NULL);
-	t->chan = !m->chan ? NULL: g_convert_with_fallback(m->chan, -1, to, from, "?", NULL, NULL, NULL);
-
-	/* if any of the conversions have failed.. */
-	if((m->src && !t->src) || (m->dst && !t->dst) || (m->text && !t->text)
-	    || (m->supp && !t->supp) || (m->chan && !t->chan)) {
-		delete_converted_msg(t);
-		return NULL;
-	}
-
-	return t;
-}
-
-static GList *
-decode_chanlist(const char * chanstring)
-{
-	const char * p, * next;
-	char * name;
-	GList * chanlist = NULL;
-	int len;
-
-	g_assert(chanstring);
-
-	len = strlen(chanstring);
-
-	/* check that the chanstring is valid */
-	if (len<3 || chanstring[0]!='#' || chanstring[len-1]!='#') {
-		return NULL;
-	}
-
-	/* parse the chanstring */
-	p = chanstring + 1;
-	do {
-		/* extract name */
-		next = strchr(p, '#');
-		g_assert(next);
-
-		/* make sure that the channel name is valid */
-		len = next - p;
-		if (len>0 && len<=MAX_CHAN_LENGTH) {
-			/* malloc a copy */
-			name = g_malloc(len+1);
-			memcpy(name, p, len);
-			name[len] = '\0';
-
-			/* insert this into list */
-			chanlist = g_list_append(chanlist, name);
-		}
-
-		/* seek for next channel */
-		p = next + 1;
-	} while (*p);
-
-	return chanlist;
-}
-
-static void
-free_chanlist(GList * chanlist)
-{
-	while(chanlist) {
-		g_free(chanlist->data);
-		chanlist = g_list_delete_link(chanlist, chanlist);
-	}
-}
-
-static void
-net_errno(int errno_value)
-{
-	const gchar * error_str = _(strerror(errno_value));
-
-	log_ferror(_(LOG_NET), g_strdup_printf("ERROR (%s)", error_str));
-	raise_event(EVENT_NET_ERROR, (gpointer)error_str, errno_value);
-}
-
-/*
- * net_send:
- *	sends a message to network
- */
-static void
-net_send(const qcs_msg * m)
-{
-	g_assert(m);
-
-	if(net) {
-		qcs_msg * cmsg = convert_msg_charset(m, prefs_str(PREFS_NET_ENCODING), "UTF-8");
-		if(cmsg) {
-			if(!qcs_send(net, cmsg)) {
-				net_errno(errno);
-			}
-			delete_converted_msg(cmsg);
-		} else {
-			log_error(_(LOG_NET), _(ERRSTR_ENCODING));
-		}
-	}
-}
-
-/**
- * reply_on_net_join:
- *	sends topic info & our existence to new user 
- */
-static void
-net_reply_on_net_join(const char * nick)
-{
-	qcs_msg * m;
-
-	g_assert(nick && strlen(nick));
-
-	m = qcs_newmsg();
-
-	/* send topic reply 
-	 *	XXX: don't know what to
-	 *	reply to vypresschat clients
-	 */
-
-	/*
-	m->msg = QCS_MSG_TOPIC_REPLY;
-	qcs_msgset(m, QCS_DST, nick);
-	qcs_msgset(m, QCS_TEXT, "");
-	nett_send(m);
-	*/
-
-	/* send refresh reply */
-	m->msg = QCS_MSG_REFRESH_ACK;
-	m->umode = net_qcs_mode(my_mode());
-	m->uactive = gui_is_active();
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	qcs_msgset(m, QCS_DST, nick);
-
-	net_send(m);
-
-	qcs_deletemsg(m);
-}
-
-/** net_reply_to_info:
-  *	replies to info requests
-  */
-static void
-net_reply_to_info_request(const char * src)
-{
-
-	g_assert(src);
-
-	/* do the logging */
-	if(prefs_bool(PREFS_NET_VERBOSE))
-		log_fevent(_(LOG_NET), g_strdup_printf(_("host info request from %s"),src));
-
-	/* reply, if configured to */
-	if(prefs_bool(PREFS_NET_REPLY_INFO_REQ) && my_mode()!=UMODE_INVISIBLE) {
-		gchar * chanlist;
-		qcs_msg * m = qcs_newmsg();
-
-		m->msg = QCS_MSG_INFO_REPLY;
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_DST, src);
-		qcs_msgset(m, QCS_TEXT, my_nickname());
-		qcs_msgset(m, QCS_SUPP, my_motd());
-
-		qcs_msgset(m, QCS_CHAN, chanlist = sess_make_channel_list());
-		g_free(chanlist);
-
-		net_send(m);
-		qcs_deletemsg(m);
-
-		if(prefs_bool(PREFS_NET_VERBOSE))
-			log_event(_(LOG_NET), _("..replied to info request"));
-	}
-}
-
-/* net_reply_to_chanlist_request:
- *	sends reply to the QCS_MSG_CHANLIST_REQUEST message
- */
-static void
-net_reply_to_chanlist_request(gpointer user)
-{
-	if(prefs_bool(PREFS_NET_REPLY_INFO_REQ) && my_mode()!=UMODE_INVISIBLE) {
-		gchar * chanlist;
-		qcs_msg * m = qcs_newmsg();
-		m->msg = QCS_MSG_CHANLIST_REPLY;
-		qcs_msgset(m, QCS_DST, user_name_of(user));
-		qcs_msgset(m, QCS_CHAN, chanlist = sess_make_channel_list());
-		g_free(chanlist);
-
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-}
-
-static void
-net_send_refresh_ack(const gchar * name)
-{
-	g_assert(name && g_utf8_strlen(name, -1));
-
-	if(my_mode() != UMODE_INVISIBLE) {
-		qcs_msg * m = qcs_newmsg();
-		m->msg = QCS_MSG_REFRESH_ACK;
-		m->umode = net_qcs_mode(my_mode());
-		m->uactive = gui_is_active();
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_DST, name);
-
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-}
-
-static void
-net_beep_sent_from(gpointer user)
-{
-	/* send beep ack (if not invisible) */
-	if(my_mode() != UMODE_INVISIBLE) {	
-		qcs_msg * m = qcs_newmsg();
-		m->msg = QCS_MSG_BEEP_ACK;
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_DST, user_name_of(user));
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-
-	/* inform the world about beep message from 'user' */
-	raise_event(EVENT_NET_MSG_BEEP_SEND, user, 0);
-}
-
-static void
-net_message_from(
-	const gchar * nickname, const gchar * text,
-	gboolean mass_message)
-{
-	qcs_msg * m;
-	gpointer event_v[3];
-	gpointer user;
-
-	g_assert(nickname && text);
-	
-	/* check if we can receive the message in this mode
-	 */
-	if(!IS_MESSAGEABLE_MODE(my_mode())) {
-		log_fevent(_(LOG_NET), g_strdup_printf(
-			mass_message
-				? _("%s has sent a mass message however you are in %s mode")
-				: _("%s has sent you a message however you are in %s mode"),
-			nickname, user_mode_name(my_mode())
-			)
-		);
-		return;
-	}
-
-	/* check if this message is a mass message, and if we block them
-	 */
-	if(mass_message && prefs_bool(PREFS_NET_IGNORE_MASS_MSG)) {
-		log_fevent(_(LOG_NET), g_strdup_printf(
-			_("%s has sent a mass message however you have blocked them"),
-			nickname)
-		);
-		return;
-	}
-
-	if((user = user_by_name(nickname))!=0) {
-		event_v[0] = user;
-		event_v[1] = (gpointer)text;
-		event_v[2] = (gpointer)mass_message;
-		raise_event(EVENT_NET_MSG_MESSAGE, event_v, 0);
-
-		/* send confirmation that we've received his/her message */
-		m = qcs_newmsg();
-		m->msg = QCS_MSG_MESSAGE_ACK;
-		m->umode = net_qcs_mode(my_mode());
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_DST, user_name_of(user));
-		qcs_msgset(m, QCS_TEXT, my_motd());
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-}
-	
-/**
- * net_handle_netmsg:
- *	Parses a message from the network.
- *	Here we assume that m->src contains NULL if m->msg
- *	has nothing to do with m->src
- */
-static void
-net_handle_netmsg(const qcs_msg * raw_msg)
-{
-	gpointer event_v[5];
-	qcs_msg * m;
-
-	g_assert(raw_msg);
-
-	m = convert_msg_charset(raw_msg, "UTF-8", prefs_str(PREFS_NET_ENCODING));
-	if(!m) {
-		/* conversion failed */
-		log_error(_(LOG_NET), _(ERRSTR_ENCODING));
-		return;
-	}
-
-	/* check if the msg is invalid or one from ourselves */
-	if( m->msg==QCS_MSG_INVALID
-		|| (m->dst && nickname_cmp(m->dst, my_nickname()))
-		|| (m->src && !nickname_cmp(m->src, my_nickname())) )
-	{
-		goto delete_and_exit;
-	}
-
-	if(m->src && m->msg!=QCS_MSG_CHANNEL_LEAVE
-		&& m->msg!=QCS_MSG_RENAME
-		&& m->msg!=QCS_MSG_REFRESH_REQUEST
-		&& m->msg!=QCS_MSG_PRIVATE_CLOSE)
-	{
-		/* check if the user is not ignored */
-		if(prefs_list_contains(PREFS_NET_IGNORED_USERS, m->src))
-			goto delete_and_exit;
-		
-		if(!user_exists(m->src)) {
-			event_v[0] = m->src;
-			event_v[1] = GINT_TO_POINTER((m->msg==QCS_MSG_CHANNEL_JOIN
-				|| m->msg==QCS_MSG_MODE_CHANGE
-				|| m->msg==QCS_MSG_REFRESH_ACK)
-					? net_local_mode(m->umode) : UMODE_NORMAL);
-			event_v[2] = GINT_TO_POINTER(m->msg==QCS_MSG_REFRESH_ACK);
-
-			/* new user found on the network */
-			raise_event(EVENT_NET_NEW_USER, event_v, 0);
-		}
-	}
-
-	switch(m->msg) {
-	case QCS_MSG_TOPIC_REPLY:
-	case QCS_MSG_TOPIC_CHANGE:
-		if(net_type==NET_TYPE_QCHAT) {
-			/* topic is the same for all channels in QChat */
-			raise_event(EVENT_NET_MSG_TOPIC_CHANGE, m->text, 0);
-		} else {
-			/* topic is different for each channel in VyChat*/
-			event_v[0] = m->chan;
-			event_v[1] = m->text;
-			raise_event(EVENT_NET_MSG_TOPIC_CHANGE_4, event_v, 0);
-		}
-		break;
-
-	case QCS_MSG_REFRESH_REQUEST:
-		net_send_refresh_ack(m->src);
-		break;
-
-	case QCS_MSG_REFRESH_ACK:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = GINT_TO_POINTER(m->uactive);
-		raise_event(
-			EVENT_NET_MSG_REFRESH_ACK,
-			event_v, net_local_mode(m->umode));
-		break;
-
-	case QCS_MSG_INFO_REQUEST:
-		net_reply_to_info_request(m->src);
-		break;
-
-	case QCS_MSG_MESSAGE_MASS:
-	case QCS_MSG_MESSAGE_SEND:
-		net_message_from(m->src, m->text, m->msg==QCS_MSG_MESSAGE_MASS);
-		break;
-
-	case QCS_MSG_MESSAGE_ACK:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->text;
-		if(event_v[0])
-			raise_event(
-				EVENT_NET_MSG_MESSAGE_ACK,
-				event_v, net_local_mode(m->umode));
-		break;
-
-	case QCS_MSG_RENAME:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->text;
-		if(event_v[0])
-			raise_event(EVENT_NET_MSG_RENAME, event_v, 0);
-		break;
-
-	case QCS_MSG_MODE_CHANGE:
-		raise_event(
-			EVENT_NET_MSG_MODE_CHANGE,
-			user_by_name(m->src), net_local_mode(m->umode));
-		break;
-
-	case QCS_MSG_ACTIVE_CHANGE:
-		raise_event(
-			EVENT_NET_MSG_ACTIVE_CHANGE,
-			user_by_name(m->src), m->uactive);
-		break;
-
-	case QCS_MSG_CHANNEL_JOIN:
-		if(!channel_cmp(m->chan, "Main")) {
-			/* reply topic & our presence */
-			net_reply_on_net_join(m->src);
-		}
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->chan;
-		raise_event(EVENT_NET_MSG_CHANNEL_JOIN, event_v, 0);
-		break;
-
-	case QCS_MSG_CHANNEL_LEAVE:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->chan;
-		if(event_v[0])
-			raise_event(EVENT_NET_MSG_CHANNEL_LEAVE, event_v, 0);
-		break;
-
-	case QCS_MSG_CHANNEL_BROADCAST:
-	case QCS_MSG_CHANNEL_ME:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->chan;
-		event_v[2] = m->text;
-		raise_event(
-			EVENT_NET_MSG_CHANNEL_TEXT,
-			event_v, m->msg==QCS_MSG_CHANNEL_ME);
-		break;
-
-	case QCS_MSG_PRIVATE_OPEN:
-		raise_event(EVENT_NET_MSG_PRIVATE_OPEN, user_by_name(m->src), 0);
-		break;
-
-	case QCS_MSG_PRIVATE_CLOSE:
-		event_v[0] = user_by_name(m->src);
-		if(event_v[0])
-			raise_event(EVENT_NET_MSG_PRIVATE_CLOSE, event_v[0], 0);
-		break;
-
-	case QCS_MSG_PRIVATE_TEXT:
-	case QCS_MSG_PRIVATE_ME:
-		event_v[0] = user_by_name(m->src);
-		event_v[1] = m->text;
-		raise_event(EVENT_NET_MSG_PRIVATE_TEXT,
-			event_v, m->msg==QCS_MSG_PRIVATE_ME);
-		break;
-		
-	case QCS_MSG_INFO_REPLY:
-		event_v[0] = user_by_name(m->src);
-		event_v[2] = (gpointer)decode_chanlist(m->chan);
-		if(event_v[2]) {
-			event_v[1] = m->text;
-			event_v[3] = m->supp;
-			event_v[4] = GINT_TO_POINTER(m->src_ip);
-			raise_event(EVENT_NET_MSG_INFO_REPLY, event_v, 0);
-			free_chanlist((GList*)event_v[2]);
-		}
-		break;
-
-	case QCS_MSG_BEEP_SEND:
-		net_beep_sent_from(user_by_name(m->src));
-		break;
-
-	case QCS_MSG_BEEP_ACK:
-		raise_event(EVENT_NET_MSG_BEEP_ACK, user_by_name(m->src), 0);
-		break;
-		
-	case QCS_MSG_CHANLIST_REQUEST:
-		net_reply_to_chanlist_request(user_by_name(m->src));
-		break;
-		
-	case QCS_MSG_CHANLIST_REPLY:
-		event_v[0] = (gpointer)decode_chanlist(m->chan);
-		if (event_v[0]!=NULL) {
-			raise_event(EVENT_NET_MSG_CHANNEL_LIST, event_v[0], 0);
-			free_chanlist( (GList*)event_v[0] );
-		}
-		break;
-	default:
-		break;	/* NOTHING */
-	}
-	
-delete_and_exit:
-	delete_converted_msg(m);
-}
-
-static gboolean
-net_io_func(
-	GIOChannel * s,
-	GIOCondition c,
-	gpointer data)
-{
-	qcs_msg * m;
-
-	switch(c) {
-	case G_IO_IN:
-		m = qcs_newmsg();
-		qcs_recv(net, m);
-		net_handle_netmsg(m);
-		qcs_deletemsg(m);
-		break;
-	case G_IO_ERR:
-	case G_IO_HUP:
-	case G_IO_NVAL:
-		net_errno(0);
-		break;
-	default:
-		break; /* nothing else */
-	}
-
-	return TRUE;	/* leave handler untouched */
-}
-
-static void
-net_handle_my_text(
-	const char * text,
-	int me_text)		/* for "/me <text>" expressions */
-{
-	sess_id s;
-	enum session_type type;
-	qcs_msg * m;
-
-	/* get current session & check that it's channel or private */
-	s = sess_current();
-	g_assert(s);
-	type = sess_type(s);
-	if(type!=SESSTYPE_CHANNEL && type!=SESSTYPE_PRIVATE)
-		return;
-
-	/* make proto message */
-	g_assert(text);
-
-	m = qcs_newmsg();
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	qcs_msgset(m, QCS_TEXT, text);
-
-	/* set msg type & destination */
-	if(type==SESSTYPE_CHANNEL) {
-		m->msg = me_text
-			? QCS_MSG_CHANNEL_ME : QCS_MSG_CHANNEL_BROADCAST;
-		qcs_msgset(m, QCS_CHAN, sess_name(s));
-	} else {
-		m->msg = me_text
-			? QCS_MSG_PRIVATE_ME : QCS_MSG_PRIVATE_TEXT;
-		qcs_msgset(m, QCS_DST, sess_name(s));
-	}
-
-	/* send the msg */
-	net_send(m);
-
-	qcs_deletemsg(m);
-}
-
-static void
-net_handle_session_open_close(
-	sess_id s,
-	int open)	/* open(1) or close(0) */
-{
-	qcs_msg * m;
-
-	/* don't notify members of the channel if
-	 * the `PREFS_CHANNEL_GREET' config option is not set,
-	 * or we are "invisible"
-	 */
- 	if(sess_type(s)==SESSTYPE_CHANNEL
-			&& (!prefs_bool(PREFS_NET_CHANNEL_NOTIFY) || my_mode()==UMODE_INVISIBLE)
-		) return;
-
-	m = qcs_newmsg();
-
-	switch(sess_type(s)) {
-	case SESSTYPE_PRIVATE:
-		m->msg = open ? QCS_MSG_PRIVATE_OPEN: QCS_MSG_PRIVATE_CLOSE;
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_DST, sess_name(s));
-		break;
-	case SESSTYPE_CHANNEL:
-		m->msg = open ? QCS_MSG_CHANNEL_JOIN: QCS_MSG_CHANNEL_LEAVE;
-		m->umode = net_qcs_mode(my_mode());
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		qcs_msgset(m, QCS_CHAN, sess_name(s));
-		break;
-	default:
-		/* ignore status & etc open/close */
-		break;
-	}
-	if(m->msg!=QCS_MSG_INVALID) {
-		net_send(m);
-	}
-
-	qcs_deletemsg(m);
-}
-
-static void
-handle_channel_topic_enter(
-	sess_id session,
-	const char * new_topic)
-{
-	qcs_msg * m;
-
-	g_assert(session && new_topic);
-
-	/* send message */
-	m = qcs_newmsg();
-	m->msg = QCS_MSG_TOPIC_CHANGE;
-	qcs_msgset(m, QCS_CHAN, net_type==NET_TYPE_VYPRESS ? sess_name(session): "Main");
-	qcs_msgset(m, QCS_TEXT, new_topic);
-	net_send(m);
-	qcs_deletemsg(m);
-
-	/* update topics for all the channels, if we are on qchat network */
-	if(net_type==NET_TYPE_QCHAT) {
-		raise_event(EVENT_NET_MSG_TOPIC_CHANGE, (void*)new_topic, 0);
-	}
-}
-
-static void
-net_send_message_to(gpointer dst_user, const char * text)
-{
-	qcs_msg * m;
-
-	g_assert(dst_user && text);
-
-	m = qcs_newmsg();
-	m->msg = QCS_MSG_MESSAGE_SEND;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
-	qcs_msgset(m, QCS_TEXT, text);
-
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-/** net_send_chan_req
-  *	supp func to send USER_CHANLIST_REQ
-  */
-static void
-net_send_chan_req()
-{
-	qcs_msg * m;
-
-	m = qcs_newmsg();
-	m->msg = QCS_MSG_CHANLIST_REQUEST;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-/** net_send_info_req:
-  *	supp funct to send USER_INFO_REQ
-  */
-static void
-net_send_info_req(gpointer dst_user)
-{
-	qcs_msg * m;
-	
-	g_assert(dst_user);
-
-	m = qcs_newmsg();
-	m->msg = QCS_MSG_INFO_REQUEST;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
-
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-/* net_send_beep:
- *	sends BEEP to the specified user
- */
-static void
-net_send_beep(gpointer dst_user)
-{
-	qcs_msg * m = qcs_newmsg();
-	m->msg = QCS_MSG_BEEP_SEND;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
-
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-
-/** net_send_refresh_req:
-  *	supp func to send REFRESH_REQ
-  */
-static void
-net_send_refresh_req()
-{
-	qcs_msg * m = qcs_newmsg();
-	m->msg = QCS_MSG_REFRESH_REQUEST;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-/** net_send_active_change
- *	notify network if our client gui is not active
- *	(minimized, not-on-top, hidden, etc)
- */
-static void
-net_send_active_change(gboolean is_active)
-{
-	qcs_msg * m = qcs_newmsg();
-	m->msg = QCS_MSG_ACTIVE_CHANGE;
-	m->uactive = is_active;
-	qcs_msgset(m, QCS_SRC, my_nickname());
-
-	net_send(m);
-	qcs_deletemsg(m);
-}
-
-static gboolean
-net_prefs_type_validator(const gchar * prefs_name, gpointer user_data)
-{
-	return prefs_int(prefs_name) < NET_TYPE_NUM;
-}
-
-static gboolean
-net_prefs_port_validator(const gchar * prefs_name, gpointer user_data)
-{
-	return prefs_int(prefs_name) <= G_MAXUINT16;
-}
-
-static gboolean
-net_prefs_encoding_validator(const gchar * prefs_name, gpointer user_data)
-{
-	gchar * enc_test;
-	const gchar * new_encoding = prefs_str(prefs_name);
-
-	enc_test = g_convert("a", -1, "UTF-8", new_encoding, NULL, NULL, NULL);
-	if(!enc_test) {
-		log_ferror(NULL, g_strdup_printf(
-			_("Charset encoding \"%s\" is invalid or not supported on this system"),
-			new_encoding));
-		return FALSE;
-	}
-	g_free(enc_test);
-	return TRUE;
-}
-
-static void
-net_prefs_main_nickname_changed_cb(const gchar * prefs_name)
-{
-	qcs_msg * m;
-
-	if(my_mode()!=UMODE_INVISIBLE) {
-		/* we've been started & online: send MSG_RENAME */
-		m = qcs_newmsg();
-		m->msg = QCS_MSG_RENAME;
-		qcs_msgset(m, QCS_SRC, old_nickname->str);
-		qcs_msgset(m, QCS_TEXT, my_nickname());
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-
-	/* preserve old nickname */
-	g_string_assign(old_nickname, my_nickname());
-}
-
-static void
-net_prefs_main_mode_changed_cb(const gchar * prefs_name)
-{
-	qcs_msg * m;
-
-	/* send MSG_MODE_CHANGE to network */
-	if(my_mode()!=UMODE_INVISIBLE) {
-		m = qcs_newmsg();
-		m->msg = QCS_MSG_MODE_CHANGE;
-		m->umode = net_qcs_mode(my_mode());
-		qcs_msgset(m, QCS_SRC, my_nickname());
-		net_send(m);
-		qcs_deletemsg(m);
-	}
-}
-
-static void
-net_prefs_net_settings_changed_cb(const gchar * prefs_name)
-{
-	if(app_status()==APP_RUNNING) {
-		gboolean do_reconnect;
-
-		if(!strcmp(prefs_name, PREFS_NET_TYPE))
-			do_reconnect = 1;
-		else if(!strcmp(prefs_name, PREFS_NET_PORT))
-			do_reconnect = 1;
-		else if(!strcmp(prefs_name, PREFS_NET_USE_MULTICAST))
-			do_reconnect = prefs_int(PREFS_NET_TYPE)==NET_TYPE_VYPRESS;
-		else if(!strcmp(prefs_name, PREFS_NET_MULTICAST_ADDR))
-			do_reconnect =
-				prefs_int(PREFS_NET_TYPE)==NET_TYPE_VYPRESS
-				&& prefs_bool(PREFS_NET_USE_MULTICAST);
-		else if(!strcmp(prefs_name, PREFS_NET_BROADCAST_MASK))
-			do_reconnect =
-				prefs_int(PREFS_NET_TYPE)!=NET_TYPE_VYPRESS
-				|| !prefs_bool(PREFS_NET_USE_MULTICAST);
-		else
-			do_reconnect = 0;
-					
-		if(do_reconnect) {
-			net_disconnect();
-			net_connect();
-		}
-	}
-}
-
-static void
-net_prefs_net_is_configured_changed_cb(const gchar * prefs_name)
-{
-	if(prefs_bool(PREFS_NET_IS_CONFIGURED)
-			&& !net_connected()
-			&& app_status()==APP_RUNNING)
-		net_connect();
-}
-
-static void
-net_register_prefs()
-{
-	prefs_register(PREFS_NET_TYPE,		PREFS_TYPE_UINT,
-		_("Network type"), net_prefs_type_validator, NULL);
-	prefs_register(PREFS_NET_PORT,		PREFS_TYPE_UINT,
-		_("Network port"), net_prefs_port_validator, NULL);
-	prefs_register(PREFS_NET_IS_CONFIGURED,	PREFS_TYPE_BOOL,
-		_("Network is configured"), NULL, NULL);
-	prefs_register(PREFS_NET_BROADCAST_MASK, PREFS_TYPE_UINT,
-		_("Network broadcast mask"), NULL, NULL);
-	prefs_register(PREFS_NET_USE_MULTICAST, PREFS_TYPE_BOOL,
-		_("Use multicast networking"), NULL, NULL);
-	prefs_register(PREFS_NET_MULTICAST_ADDR, PREFS_TYPE_UINT,
-		_("Network multicast address"), NULL, NULL);
-	prefs_register(PREFS_NET_VERBOSE,	PREFS_TYPE_BOOL, 
-		_("Verbosely report network events"), NULL, NULL);
-	prefs_register(PREFS_NET_CHANNEL_NOTIFY,PREFS_TYPE_BOOL,
-		_("Notify channel users on join/leave"), NULL, NULL);
-	prefs_register(PREFS_NET_IGNORE_MASS_MSG,PREFS_TYPE_BOOL,
-		_("Ignore mass messages"), NULL, NULL);
-	prefs_register(PREFS_NET_ENCODING,	PREFS_TYPE_STR,
-		_("Network charset encoding"), net_prefs_encoding_validator, NULL);
-	prefs_register(PREFS_NET_REPLY_INFO_REQ,PREFS_TYPE_BOOL, 
-		_("Reply to user information requests"), NULL, NULL);
-	prefs_register(PREFS_NET_MOTD,		PREFS_TYPE_STR, 
-		_("User information text"), NULL, NULL);
-	prefs_register(PREFS_NET_MOTD_WHEN_AWAY,PREFS_TYPE_STR,
-		_("User information text when away"), NULL, NULL);
-	prefs_register(PREFS_NET_IGNORED_USERS, PREFS_TYPE_LIST,
-		_("Ignored users"), NULL, NULL);
-
-	prefs_add_notifier(PREFS_MAIN_NICKNAME, (GHookFunc)net_prefs_main_nickname_changed_cb);
-	prefs_add_notifier(PREFS_MAIN_MODE, (GHookFunc)net_prefs_main_mode_changed_cb);
-
-	prefs_add_notifier(PREFS_NET_PORT, (GHookFunc)net_prefs_net_settings_changed_cb);
-	prefs_add_notifier(PREFS_NET_TYPE, (GHookFunc)net_prefs_net_settings_changed_cb);
-	prefs_add_notifier(PREFS_NET_BROADCAST_MASK, (GHookFunc)net_prefs_net_settings_changed_cb);
-	prefs_add_notifier(PREFS_NET_MULTICAST_ADDR, (GHookFunc)net_prefs_net_settings_changed_cb);
-	prefs_add_notifier(PREFS_NET_USE_MULTICAST, (GHookFunc)net_prefs_net_settings_changed_cb);
-
-	prefs_add_notifier(PREFS_NET_IS_CONFIGURED, (GHookFunc)net_prefs_net_is_configured_changed_cb);
-}
-
-static void
-net_preset_prefs()
-{
-	/* set default values */
-	prefs_set(PREFS_NET_CHANNEL_NOTIFY, TRUE);
-	prefs_set(PREFS_NET_ENCODING, NET_DEFAULT_CHARSET);
-	prefs_set(PREFS_NET_REPLY_INFO_REQ, TRUE);
-	prefs_set(PREFS_NET_MOTD_WHEN_AWAY, _("User is away"));
-	prefs_set(PREFS_NET_BROADCAST_MASK, 0xffffffff);	/* 255.255.255.255 */
-	prefs_set(PREFS_NET_MULTICAST_ADDR, 0xe3000002);	/* 227.0.0.2 */
-}
-
-static void
-net_event_cb(enum app_event_enum e, gpointer p, int i)
-{
-	switch(e) {
-	case EVENT_MAIN_INIT:
-		net = NULL;
-		net_event_source = 0;
-		old_nickname = g_string_new(NULL);
-		break;
-
-	case EVENT_MAIN_REGISTER_PREFS:
-		net_register_prefs();
-		break;
-
-	case EVENT_MAIN_PRESET_PREFS:
-		net_preset_prefs();
-		break;
-
-	case EVENT_MAIN_START:
-		/* gui_netselect_dlg should popup it's dialog
-		 * if the network is not configured
-		 */
-		if(prefs_bool(PREFS_NET_IS_CONFIGURED))
-			net_connect();
-		break;
-
-	case EVENT_MAIN_PRECLOSE:
-		net_disconnect();
-		break;
-
-	case EVENT_MAIN_CLOSE:
-		g_string_free(old_nickname, TRUE);
-		old_nickname = NULL;
-		break;
-
-	case EVENT_SESSION_OPENED:
-	case EVENT_SESSION_CLOSED:
-		net_handle_session_open_close(
-			(sess_id)p,
-			e==EVENT_SESSION_OPENED);
-		break;
-
-	case EVENT_SESSION_TOPIC_ENTER:
-		if(sess_type(EVENT_V(p, 0))==SESSTYPE_CHANNEL)
-			handle_channel_topic_enter(EVENT_V(p,0), EVENT_V(p,1));
-		break;
-
-	case EVENT_CMDPROC_SESSION_TEXT:
-		net_handle_my_text((const char *)p, i);
-		break;
-	case EVENT_MESSAGE_SEND:
-		net_send_message_to(EVENT_V(p,0), (const char *)EVENT_V(p,1));
-		break;
-	case EVENT_USER_NET_UPDATE_REQ:
-		net_send_refresh_req();
-		break;
-	case EVENT_IFACE_USER_INFO_REQ:
-		net_send_info_req(p);
-		break;
-	case EVENT_IFACE_USER_BEEP_REQ:
-		net_send_beep(p);
-		break;
-	case EVENT_IFACE_REQUEST_NET_CHANNELS:
-		net_send_chan_req();
-		break;
-	case EVENT_IFACE_ACTIVE_CHANGE:
-		net_send_active_change((gboolean)i);
-		break;
-	default:
-		break;	/* nothing else */
-	}
-}
-
-static gboolean
-net_connect()
-{
-	GIOChannel * channel;
-	int rx_socket;
-	enum net_type_enum type = prefs_int(PREFS_NET_TYPE);
-	unsigned short port = prefs_int(PREFS_NET_PORT);
-
-	g_assert(net==NULL);
-
-	/* check network type num */
-	if(type>=NET_TYPE_NUM) {
-		log_error(_(LOG_NET), ("invalid network type specified: falling back to QuickChat"));
-		type = NET_TYPE_QCHAT;
-	}
-
-	/* notify everyone that we're about to connect to the network */
-	raise_event(EVENT_NET_PRECONNECT, 0, 0);
-
-	net_type = type;
-
-	/* do the real connecting */
-	if(type==QCS_PROTO_VYPRESS) {
-		int use_multicast = prefs_bool(PREFS_NET_USE_MULTICAST);
-		net = qcs_open(
-			QCS_PROTO_VYPRESS,
-			use_multicast ? QCS_PROTO_OPT_MULTICAST: 0,
-			use_multicast
-				? prefs_int(PREFS_NET_MULTICAST_ADDR)
-				: prefs_int(PREFS_NET_BROADCAST_MASK),
-			port);
-	} else {
-		net = qcs_open(QCS_PROTO_QCHAT, 0, prefs_int(PREFS_NET_BROADCAST_MASK), port);
-	}
-
-	/* check for errors */
-	if(!net) {
-		log_ferror(_(LOG_NET), g_strdup_printf(
-			_("failed to connect to %s network on port %hd: %s"),
-				net_name_of_type(type), port, strerror(errno)));
-		log_error(_(LOG_NET),
-			_("check if there are any programs running on the same port"
-				" and your firewall settings"));
-		return FALSE;
-	}
-
-	/* install glib event handler on socket */
-	qcs_rxsocket(net, &rx_socket);
-	channel = g_io_channel_unix_new(rx_socket);
-	net_event_source = g_io_add_watch(
-			channel,
-			G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
-			net_io_func, 0);
-	g_io_channel_unref(channel);
-
-	log_fevent(_(LOG_NET), g_strdup_printf(
-		_("connected to %s network on port %hd"), net_name_of_type(type), port));
-
-	/* notify that we've connected */
-	raise_event(EVENT_NET_CONNECTED, 0,0);
-
-	return TRUE;
-}
-
-static void
-net_disconnect()
-{
-	if(net) {
-		/* notify everyone of our evil intentions */
-		raise_event(EVENT_NET_PREDISCONNECT, 0,0);
-
-		/* remove io_chan */
-		g_source_remove(net_event_source);
-		net_event_source = 0;
-
-		/* close link */
-		qcs_close(net);
-		net = NULL;
-
-		raise_event(EVENT_NET_DISCONNECTED, 0,0);
-	}
-}
-
-/** exported routines
-  *************************/
-void net_register()
-{
-	register_event_cb(
-		net_event_cb,
-		EVENT_MAIN | EVENT_CMDPROC | EVENT_IFACE
-		| EVENT_SESSION | EVENT_MESSAGE | EVENT_USER);
-}
-
-gboolean net_connected()
-{
-	return net!=NULL;
-}
-
-const gchar *
-net_name_of_type(enum net_type_enum t)
-{
-	switch(t) {
-	case NET_TYPE_QCHAT:	return "quickChat";
-	case NET_TYPE_VYPRESS:	return "Vypress Chat";
-	default:
-		break;	/* nothing else */
-	}
-	return "(invalid network type)";
+/*
+ * net.c: network routines
+ * Copyright (C) 2002-2004 Saulius Menkevicius
+ *
+ * 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
+ *
+ * $Id: net.c,v 1.36 2005/01/06 10:16:09 bobas Exp $
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "libqcproto/qcproto.h"
+
+#include "main.h"
+#include "net.h"
+#include "prefs.h"
+#include "sess.h"
+#include "user.h"
+#include "gui.h"
+
+#define NET_DEFAULT_CHARSET "ISO-8859-1"
+
+/** static vars
+  *************************/
+static qcs_link net;
+static enum net_type_enum net_type;
+static guint net_event_source;
+static GString * old_nickname;
+static time_t last_time_refresh_ack;
+
+#define LOG_NET		N_("Network")
+
+#define ERRSTR_ENCODING	N_("Charset encoding/decoding error; \
+please check \"Network charset\" under the \"Network\" on the Preferences dialog")
+
+/** local routines
+  *************************/
+static gboolean net_connect();
+static void net_disconnect();
+
+static enum user_mode_enum
+net_local_mode(int qcs_umode)
+{
+	enum user_mode_enum m;
+
+	switch(qcs_umode) {
+	case QCS_UMODE_NORMAL:	m = UMODE_NORMAL;	break;
+	case QCS_UMODE_OFFLINE:	m = UMODE_OFFLINE;	break;
+	case QCS_UMODE_DND:	m = UMODE_DND;		break;
+	case QCS_UMODE_AWAY:	m = UMODE_AWAY;		break;
+	case QCS_UMODE_INVALID:	m = UMODE_NULL;		break;
+	}
+	return m;
+}
+
+static int
+net_qcs_mode(enum user_mode_enum local_mode)
+{
+	int m;
+
+	switch(local_mode) {
+	case UMODE_NORMAL:
+	case UMODE_INVISIBLE:
+		m = QCS_UMODE_NORMAL;
+		break;
+	case UMODE_DND:		m = QCS_UMODE_DND;	break;
+	case UMODE_AWAY:	m = QCS_UMODE_AWAY;	break;
+	case UMODE_OFFLINE:	m = QCS_UMODE_OFFLINE;	break;
+	default:		m = QCS_UMODE_INVALID;	break;
+	}
+	return m;
+}
+
+static void
+delete_converted_msg(qcs_msg * m)
+{
+	if(m->src) g_free(m->src);
+	if(m->dst) g_free(m->dst);
+	if(m->text) g_free(m->text);
+	if(m->supp) g_free(m->supp);
+	if(m->chan) g_free(m->chan);
+	g_free(m);
+}
+
+static qcs_msg *
+convert_msg_charset(const qcs_msg * m, const gchar * to, const gchar * from)
+{
+	qcs_msg * t = g_new0(qcs_msg, 1);
+	
+	t->msg = m->msg;
+	t->umode = m->umode;
+	t->uactive = m->uactive;
+	t->src_ip = m->src_ip;
+	t->src = !m->src ? NULL: g_convert_with_fallback(m->src, -1, to, from, "?", NULL, NULL, NULL);
+	t->dst = !m->dst ? NULL: g_convert_with_fallback(m->dst, -1, to, from, "?", NULL, NULL, NULL);
+	t->text = !m->text ? NULL: g_convert_with_fallback(m->text, -1, to, from, "?", NULL, NULL, NULL);
+	t->supp = !m->supp ? NULL: g_convert_with_fallback(m->supp, -1, to, from, "?", NULL, NULL, NULL);
+	t->chan = !m->chan ? NULL: g_convert_with_fallback(m->chan, -1, to, from, "?", NULL, NULL, NULL);
+
+	/* if any of the conversions have failed.. */
+	if((m->src && !t->src) || (m->dst && !t->dst) || (m->text && !t->text)
+	    || (m->supp && !t->supp) || (m->chan && !t->chan)) {
+		delete_converted_msg(t);
+		return NULL;
+	}
+
+	return t;
+}
+
+static GList *
+decode_chanlist(const char * chanstring)
+{
+	const char * p, * next;
+	char * name;
+	GList * chanlist = NULL;
+	int len;
+
+	g_assert(chanstring);
+
+	len = strlen(chanstring);
+
+	/* check that the chanstring is valid */
+	if (len<3 || chanstring[0]!='#' || chanstring[len-1]!='#') {
+		return NULL;
+	}
+
+	/* parse the chanstring */
+	p = chanstring + 1;
+	do {
+		/* extract name */
+		next = strchr(p, '#');
+		g_assert(next);
+
+		/* make sure that the channel name is valid */
+		len = next - p;
+		if (len>0 && len<=MAX_CHAN_LENGTH) {
+			/* malloc a copy */
+			name = g_malloc(len+1);
+			memcpy(name, p, len);
+			name[len] = '\0';
+
+			/* insert this into list */
+			chanlist = g_list_append(chanlist, name);
+		}
+
+		/* seek for next channel */
+		p = next + 1;
+	} while (*p);
+
+	return chanlist;
+}
+
+static void
+free_chanlist(GList * chanlist)
+{
+	while(chanlist) {
+		g_free(chanlist->data);
+		chanlist = g_list_delete_link(chanlist, chanlist);
+	}
+}
+
+static void
+net_errno(int errno_value)
+{
+	const gchar * error_str = _(strerror(errno_value));
+
+	log_ferror(_(LOG_NET), g_strdup_printf("=( ERROR (%s)", error_str));
+	raise_event(EVENT_NET_ERROR, (gpointer)error_str, errno_value);
+}
+
+/*
+ * net_send:
+ *	sends a message to network
+ */
+static void
+net_send(const qcs_msg * m)
+{
+	g_assert(m);
+
+	if(net) {
+		qcs_msg * cmsg = convert_msg_charset(m, (prefs_bool(PREFS_NET_CHARSET_CHOICE) ? prefs_str(PREFS_NET_ENCODING) : prefs_str(PREFS_NET_SECONDARY_ENCODING)), "UTF-8");		
+			
+		if(cmsg!=NULL) {
+			if(!qcs_send(net,(qcs_msg *) cmsg)) {
+				net_errno(errno);
+			}
+			delete_converted_msg(cmsg);
+		} else {
+			log_error(_(LOG_NET), _(ERRSTR_ENCODING));
+		}
+	}
+}
+
+/**
+ * reply_on_net_join:
+ *	sends topic info & our existence to new user 
+ */
+static void
+net_reply_on_net_join(const char * nick)
+{
+	qcs_msg * m;
+
+	g_assert(nick && strlen(nick));
+
+	m = qcs_newmsg();
+
+	/* send topic reply 
+	 *	XXX: don't know what to
+	 *	reply to vypresschat clients
+	 */
+
+	/*
+	m->msg = QCS_MSG_TOPIC_REPLY;
+	qcs_msgset(m, QCS_DST, nick);
+	qcs_msgset(m, QCS_TEXT, "");
+	nett_send(m);
+	*/
+
+	/* send refresh reply */
+	m->msg = QCS_MSG_REFRESH_ACK;
+	m->umode = net_qcs_mode(my_mode());
+	m->uactive = gui_is_active();
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	qcs_msgset(m, QCS_DST, nick);
+	m->src_ip=user_ip_of(user_by_name(nick));
+	
+	net_send(m);
+	log_error(_(LOG_NET), "QCS_MSG_REFRESH_ACK");
+	qcs_deletemsg(m);
+}
+
+/** net_reply_to_info:
+  *	replies to info requests
+  */
+static void
+net_reply_to_info_request(const char * src)
+{
+
+	g_assert(src);
+
+	/* do the logging */
+	if(prefs_bool(PREFS_NET_VERBOSE))
+		log_fevent(_(LOG_NET), g_strdup_printf(_("host info request from %s"),src));
+
+	/* reply, if configured to */
+	if(prefs_bool(PREFS_NET_REPLY_INFO_REQ) && my_mode()!=UMODE_INVISIBLE) {
+		gchar * chanlist;
+		qcs_msg * m = qcs_newmsg();
+
+		m->msg = QCS_MSG_INFO_REPLY;
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_DST, src);
+		qcs_msgset(m, QCS_TEXT, my_nickname());
+		qcs_msgset(m, QCS_SUPP, my_motd());
+
+		qcs_msgset(m, QCS_CHAN, chanlist = sess_make_channel_list());
+		g_free(chanlist);
+		m->src_ip=user_ip_of(user_by_name(src));
+		
+		net_send(m);
+		qcs_deletemsg(m);
+
+		if(prefs_bool(PREFS_NET_VERBOSE))
+			log_event(_(LOG_NET), _("..replied to info request"));
+	}
+}
+
+/* net_reply_to_chanlist_request:
+ *	sends reply to the QCS_MSG_CHANLIST_REQUEST message
+ */
+static void
+net_reply_to_chanlist_request(gpointer user)
+{
+	if(prefs_bool(PREFS_NET_REPLY_INFO_REQ) && my_mode()!=UMODE_INVISIBLE) {
+		gchar * chanlist;
+		qcs_msg * m = qcs_newmsg();
+		m->msg = QCS_MSG_CHANLIST_REPLY;
+		qcs_msgset(m, QCS_DST, user_name_of(user));
+		qcs_msgset(m, QCS_CHAN, chanlist = sess_make_channel_list());
+		g_free(chanlist);
+		m->src_ip=user_ip_of(user);
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+}
+
+
+
+static void
+net_send_refresh_ack(const gchar * name)
+{
+	g_assert(name && g_utf8_strlen(name, -1));	
+	if((my_mode() != UMODE_INVISIBLE)&&((time(NULL)-last_time_refresh_ack)>1)) {
+		qcs_msg * m = qcs_newmsg();
+		m->msg = QCS_MSG_REFRESH_ACK;
+		m->umode = net_qcs_mode(my_mode());
+		m->uactive = gui_is_active();
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_DST, name);
+		m->src_ip=user_ip_of(user_by_name(name)); //unshure 
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+	last_time_refresh_ack = time(NULL);
+}
+
+static void
+net_beep_sent_from(gpointer user)
+{
+	/* send beep ack (if not invisible) */
+	if(my_mode() != UMODE_INVISIBLE) {	
+		qcs_msg * m = qcs_newmsg();
+		m->msg = QCS_MSG_BEEP_ACK;
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_DST, user_name_of(user));
+		m->src_ip=user_ip_of(user);
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+
+	/* inform the world about beep message from 'user' */
+	raise_event(EVENT_NET_MSG_BEEP_SEND, user, 0);
+}
+
+static void
+net_message_from(
+	const gchar * nickname, const gchar * text,
+	gboolean mass_message)
+{
+	qcs_msg * m;
+	gpointer event_v[3];
+	gpointer user;
+
+	g_assert(nickname && text);
+	
+	/* check if we can receive the message in this mode
+	 */
+	if(!IS_MESSAGEABLE_MODE(my_mode())) {
+		log_fevent(_(LOG_NET), g_strdup_printf(
+			mass_message
+				? _("%s has sent a mass message however you are in %s mode")
+				: _("%s has sent you a message however you are in %s mode"),
+			nickname, user_mode_name(my_mode())
+			)
+		);
+		return;
+	}
+
+	/* check if this message is a mass message, and if we block them
+	 */
+	if(mass_message && prefs_bool(PREFS_NET_IGNORE_MASS_MSG)) {
+		log_fevent(_(LOG_NET), g_strdup_printf(
+			_("%s has sent a mass message however you have blocked them"),
+			nickname)
+		);
+		return;
+	}
+
+	if((user = user_by_name(nickname))!=0) {
+		event_v[0] = user;
+		event_v[1] = (gpointer)text;
+		event_v[2] = (gpointer)mass_message;
+		raise_event(EVENT_NET_MSG_MESSAGE, event_v, 0);
+
+		/* send confirmation that we've received his/her message */
+		m = qcs_newmsg();
+		m->msg = QCS_MSG_MESSAGE_ACK;
+		m->umode = net_qcs_mode(my_mode());
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_DST, user_name_of(user));
+		qcs_msgset(m, QCS_TEXT, my_motd());
+		m->src_ip=user_ip_of(user);
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+}
+	
+/**
+ * net_handle_netmsg:
+ *	Parses a message from the network.
+ *	Here we assume that m->src contains NULL if m->msg
+ *	has nothing to do with m->src
+ */
+static void
+net_handle_netmsg(const qcs_msg * raw_msg)
+{
+	gpointer event_v[5];
+	qcs_msg * m;
+
+	g_assert(raw_msg);
+
+	m = convert_msg_charset(raw_msg, "UTF-8", prefs_str(PREFS_NET_ENCODING));
+	if(!m) {
+	m = convert_msg_charset(raw_msg, "UTF-8", prefs_str(PREFS_NET_SECONDARY_ENCODING));//prefs_str(PREFS_NET_ENCODING)
+	}else if(!m) {
+
+		/* conversion failed */
+		log_error(_(LOG_NET), _(ERRSTR_ENCODING));
+		return;
+	}
+
+	/* check if the msg is invalid or one from ourselves */
+	if( m->msg==QCS_MSG_INVALID
+		|| (m->dst && nickname_cmp(m->dst, my_nickname()))
+		|| (m->src && !nickname_cmp(m->src, my_nickname())) )
+	{
+		goto delete_and_exit;
+	}
+
+	if(m->src && m->msg!=QCS_MSG_CHANNEL_LEAVE
+		&& m->msg!=QCS_MSG_RENAME
+		&& m->msg!=QCS_MSG_REFRESH_REQUEST
+		&& m->msg!=QCS_MSG_PRIVATE_CLOSE)
+	{
+		/* check if the user is not ignored */
+		if(prefs_list_contains(PREFS_NET_IGNORED_USERS, m->src))
+			goto delete_and_exit;
+		
+		if(!user_exists(m->src)) {
+			event_v[0] = m->src;
+			event_v[1] = GINT_TO_POINTER((m->msg==QCS_MSG_CHANNEL_JOIN
+				|| m->msg==QCS_MSG_MODE_CHANGE
+				|| m->msg==QCS_MSG_REFRESH_ACK)
+					? net_local_mode(m->umode) : UMODE_NORMAL);
+			event_v[2] = GINT_TO_POINTER(m->msg==QCS_MSG_REFRESH_ACK);
+			event_v[3] = GINT_TO_POINTER(m->src_ip);
+
+			/* new user found on the network */
+			raise_event(EVENT_NET_NEW_USER, event_v, 0);
+		}
+	}
+
+	switch(m->msg) {
+	case QCS_MSG_TOPIC_REPLY:
+	case QCS_MSG_TOPIC_CHANGE:
+		if(net_type==NET_TYPE_QCHAT) {
+			/* topic is the same for all channels in QChat */
+			raise_event(EVENT_NET_MSG_TOPIC_CHANGE, m->text, 0);
+		} else {
+			/* topic is different for each channel in VyChat*/
+			event_v[0] = m->chan;
+			event_v[1] = m->text;
+			raise_event(EVENT_NET_MSG_TOPIC_CHANGE_4, event_v, 0);
+		}
+		break;
+
+	case QCS_MSG_REFRESH_REQUEST:
+		net_send_refresh_ack(m->src);
+		break;
+
+	case QCS_MSG_REFRESH_ACK:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = GINT_TO_POINTER(m->uactive);
+		raise_event(
+			EVENT_NET_MSG_REFRESH_ACK,
+			event_v, net_local_mode(m->umode));
+		break;
+
+	case QCS_MSG_INFO_REQUEST:
+		net_reply_to_info_request(m->src);
+		break;
+
+	case QCS_MSG_MESSAGE_MASS:
+	case QCS_MSG_MESSAGE_SEND:
+		net_message_from(m->src, m->text, m->msg==QCS_MSG_MESSAGE_MASS);
+		break;
+
+	case QCS_MSG_MESSAGE_ACK:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->text;
+		if(event_v[0])
+			raise_event(
+				EVENT_NET_MSG_MESSAGE_ACK,
+				event_v, net_local_mode(m->umode));
+		break;
+
+	case QCS_MSG_RENAME:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->text;
+		if(event_v[0])
+			raise_event(EVENT_NET_MSG_RENAME, event_v, 0);
+		break;
+
+	case QCS_MSG_MODE_CHANGE:
+		raise_event(
+			EVENT_NET_MSG_MODE_CHANGE,
+			user_by_name(m->src), net_local_mode(m->umode));
+		break;
+
+	case QCS_MSG_ACTIVE_CHANGE:
+		raise_event(
+			EVENT_NET_MSG_ACTIVE_CHANGE,
+			user_by_name(m->src), m->uactive);
+		break;
+
+	case QCS_MSG_CHANNEL_JOIN:
+		if(!channel_cmp(m->chan, "Main")) {
+			/* reply topic & our presence */
+			net_reply_on_net_join(m->src);
+		}
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->chan;
+		raise_event(EVENT_NET_MSG_CHANNEL_JOIN, event_v, 0);
+		break;
+
+	case QCS_MSG_CHANNEL_LEAVE:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->chan;
+		if(event_v[0])
+			raise_event(EVENT_NET_MSG_CHANNEL_LEAVE, event_v, 0);
+		break;
+
+	case QCS_MSG_CHANNEL_BROADCAST:
+	case QCS_MSG_CHANNEL_ME:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->chan;
+		event_v[2] = m->text;
+		raise_event(
+			EVENT_NET_MSG_CHANNEL_TEXT,
+			event_v, m->msg==QCS_MSG_CHANNEL_ME);
+		break;
+
+	case QCS_MSG_PRIVATE_OPEN:
+		raise_event(EVENT_NET_MSG_PRIVATE_OPEN, user_by_name(m->src), 0);
+		break;
+
+	case QCS_MSG_PRIVATE_CLOSE:
+		event_v[0] = user_by_name(m->src);
+		if(event_v[0])
+			raise_event(EVENT_NET_MSG_PRIVATE_CLOSE, event_v[0], 0);
+		break;
+
+	case QCS_MSG_PRIVATE_TEXT:
+	case QCS_MSG_PRIVATE_ME:
+		event_v[0] = user_by_name(m->src);
+		event_v[1] = m->text;
+		raise_event(EVENT_NET_MSG_PRIVATE_TEXT,
+			event_v, m->msg==QCS_MSG_PRIVATE_ME);
+		break;
+		
+	case QCS_MSG_INFO_REPLY:
+		event_v[0] = user_by_name(m->src);
+		event_v[2] = (gpointer)decode_chanlist(m->chan);
+		if(event_v[2]) {
+			event_v[1] = m->text;
+			event_v[3] = m->supp;
+			event_v[4] = GINT_TO_POINTER(m->src_ip);
+			raise_event(EVENT_NET_MSG_INFO_REPLY, event_v, 0);
+			free_chanlist((GList*)event_v[2]);
+		}
+		break;
+
+	case QCS_MSG_BEEP_SEND:
+		net_beep_sent_from(user_by_name(m->src));
+		break;
+
+	case QCS_MSG_BEEP_ACK:
+		raise_event(EVENT_NET_MSG_BEEP_ACK, user_by_name(m->src), 0);
+		break;
+		
+	case QCS_MSG_CHANLIST_REQUEST:
+		net_reply_to_chanlist_request(user_by_name(m->src));
+		break;
+		
+	case QCS_MSG_CHANLIST_REPLY:
+		event_v[0] = (gpointer)decode_chanlist(m->chan);
+		if (event_v[0]!=NULL) {
+			raise_event(EVENT_NET_MSG_CHANNEL_LIST, event_v[0], 0);
+			free_chanlist( (GList*)event_v[0] );
+		}
+		break;
+	default:
+		break;	/* NOTHING */
+	}
+	
+delete_and_exit:
+	delete_converted_msg(m);
+}
+
+static gboolean
+net_io_func(
+	GIOChannel * s,
+	GIOCondition c,
+	gpointer data)
+{
+	qcs_msg * m;
+
+	switch(c) {
+	case G_IO_IN:
+		m = qcs_newmsg();
+		qcs_recv(net, m);
+		net_handle_netmsg(m);
+		qcs_deletemsg(m);
+		break;
+	case G_IO_ERR:
+	case G_IO_HUP:
+	case G_IO_NVAL:
+		net_errno(0);
+		break;
+	default:
+		break; /* nothing else */
+	}
+
+	return TRUE;	/* leave handler untouched */
+}
+
+static void
+net_handle_my_text(
+	const char * text,
+	int me_text)		/* for "/me <text>" expressions */
+{
+	sess_id s;
+	enum session_type type;
+	qcs_msg * m;
+
+	/* get current session & check that it's channel or private */
+	s = sess_current();
+	g_assert(s);
+	type = sess_type(s);
+	if(type!=SESSTYPE_CHANNEL && type!=SESSTYPE_PRIVATE)
+		return;
+
+	/* make proto message */
+	g_assert(text);
+
+	m = qcs_newmsg();
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	qcs_msgset(m, QCS_TEXT, text);
+
+	/* set msg type & destination */
+	if(type==SESSTYPE_CHANNEL) {
+		m->msg = me_text
+			? QCS_MSG_CHANNEL_ME : QCS_MSG_CHANNEL_BROADCAST;
+		qcs_msgset(m, QCS_CHAN, sess_name(s));
+	} else {
+		m->msg = me_text
+			? QCS_MSG_PRIVATE_ME : QCS_MSG_PRIVATE_TEXT;
+		qcs_msgset(m, QCS_DST, sess_name(s));
+		m->src_ip=user_ip_of(user_by_name(sess_name(s)));
+	}
+
+	/* send the msg */
+	net_send(m);
+
+	qcs_deletemsg(m);
+}
+
+static void
+net_handle_session_open_close(
+	sess_id s,
+	int open)	/* open(1) or close(0) */
+{
+	qcs_msg * m;
+
+	/* don't notify members of the channel if
+	 * the `PREFS_CHANNEL_GREET' config option is not set,
+	 * or we are "invisible"
+	 */
+ 	if(sess_type(s)==SESSTYPE_CHANNEL
+			&& (!prefs_bool(PREFS_NET_CHANNEL_NOTIFY) || my_mode()==UMODE_INVISIBLE)
+		) return;
+
+	m = qcs_newmsg();
+
+	switch(sess_type(s)) {
+	case SESSTYPE_PRIVATE:
+		m->msg = open ? QCS_MSG_PRIVATE_OPEN: QCS_MSG_PRIVATE_CLOSE;
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_DST, sess_name(s));
+		m->src_ip=user_ip_of(user_by_name(sess_name(s)));
+		break;
+	case SESSTYPE_CHANNEL:
+		m->msg = open ? QCS_MSG_CHANNEL_JOIN: QCS_MSG_CHANNEL_LEAVE;
+		m->umode = net_qcs_mode(my_mode());
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		qcs_msgset(m, QCS_CHAN, sess_name(s));
+		break;
+	default:
+		/* ignore status & etc open/close */
+		break;
+	}
+	if(m->msg!=QCS_MSG_INVALID) {
+		net_send(m);
+	}
+
+	qcs_deletemsg(m);
+}
+
+static void
+handle_channel_topic_enter(
+	sess_id session,
+	const char * new_topic)
+{
+	qcs_msg * m;
+
+	g_assert(session && new_topic);
+
+	/* send message */
+	m = qcs_newmsg();
+	m->msg = QCS_MSG_TOPIC_CHANGE;
+	qcs_msgset(m, QCS_CHAN, net_type==NET_TYPE_VYPRESS ? sess_name(session): "Main");
+	qcs_msgset(m, QCS_TEXT, new_topic);
+	if(sess_type(session)!=SESSTYPE_CHANNEL)
+		m->src_ip=user_ip_of(user_by_name(sess_name(session)));
+	net_send(m);
+	qcs_deletemsg(m);
+
+	/* update topics for all the channels, if we are on qchat network */
+	if(net_type==NET_TYPE_QCHAT) {
+		raise_event(EVENT_NET_MSG_TOPIC_CHANGE, (void*)new_topic, 0);
+	}
+}
+
+static void
+net_send_message_to(gpointer dst_user, const char * text, gboolean mass_message)
+{
+	qcs_msg * m;
+
+	g_assert(dst_user && text);
+
+	m = qcs_newmsg();
+	m->msg =(mass_message==TRUE ? QCS_MSG_MESSAGE_MASS : QCS_MSG_MESSAGE_SEND) ;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
+	qcs_msgset(m, QCS_TEXT, text);
+	m->src_ip=user_ip_of(dst_user);
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+
+/** net_send_chan_req
+  *	supp func to send USER_CHANLIST_REQ
+  */
+static void
+net_send_chan_req()
+{
+	qcs_msg * m;
+
+	m = qcs_newmsg();
+	m->msg = QCS_MSG_CHANLIST_REQUEST;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+/** net_send_info_req:
+  *	supp funct to send USER_INFO_REQ
+  */
+static void
+net_send_info_req(gpointer dst_user)
+{
+	qcs_msg * m;
+	
+	g_assert(dst_user);
+
+	m = qcs_newmsg();
+	m->msg = QCS_MSG_INFO_REQUEST;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
+	m->src_ip=user_ip_of(dst_user);
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+/* net_send_beep:
+ *	sends BEEP to the specified user
+ */
+static void
+net_send_beep(gpointer dst_user)
+{
+	qcs_msg * m = qcs_newmsg();
+	m->msg = QCS_MSG_BEEP_SEND;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	qcs_msgset(m, QCS_DST, user_name_of(dst_user));
+	m->src_ip=user_ip_of(dst_user);
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+
+/** net_send_refresh_req:
+  *	supp func to send REFRESH_REQ
+  */
+static void
+net_send_refresh_req()
+{
+	qcs_msg * m = qcs_newmsg();
+	m->msg = QCS_MSG_REFRESH_REQUEST;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+/** net_send_active_change
+ *	notify network if our client gui is not active
+ *	(minimized, not-on-top, hidden, etc)
+ */
+static void
+net_send_active_change(gboolean is_active)
+{
+	qcs_msg * m = qcs_newmsg();
+	m->msg = QCS_MSG_ACTIVE_CHANGE;
+	m->uactive = is_active;
+	qcs_msgset(m, QCS_SRC, my_nickname());
+	net_send(m);
+	qcs_deletemsg(m);
+}
+
+static gboolean
+net_prefs_type_validator(const gchar * prefs_name, gpointer user_data)
+{
+	return prefs_int(prefs_name) < NET_TYPE_NUM;
+}
+
+static gboolean
+net_prefs_port_validator(const gchar * prefs_name, gpointer user_data)
+{
+	return prefs_int(prefs_name) <= G_MAXUINT16;
+}
+
+static gboolean
+net_prefs_encoding_validator(const gchar * prefs_name, gpointer user_data)
+{
+	gchar * enc_test;
+	const gchar * new_encoding = prefs_str(prefs_name);
+
+	
+	enc_test = g_convert("a", -1, "UTF-8", new_encoding, NULL, NULL, NULL);
+	if(!enc_test) {
+		log_ferror(NULL, g_strdup_printf(
+			_("Charset encoding \"%s\" is invalid or not supported on this system"),
+			new_encoding));
+		return FALSE;
+	}
+	g_free(enc_test);
+	return TRUE;
+}
+
+static void
+net_prefs_main_nickname_changed_cb(const gchar * prefs_name)
+{
+	qcs_msg * m;
+
+	if(my_mode()!=UMODE_INVISIBLE) {
+		/* we've been started & online: send MSG_RENAME */
+		m = qcs_newmsg();
+		m->msg = QCS_MSG_RENAME;
+		qcs_msgset(m, QCS_SRC, old_nickname->str);
+		qcs_msgset(m, QCS_TEXT, my_nickname());
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+
+	/* preserve old nickname */
+	g_string_assign(old_nickname, my_nickname());
+}
+
+static void
+net_prefs_main_mode_changed_cb(const gchar * prefs_name)
+{
+	qcs_msg * m;
+
+	/* send MSG_MODE_CHANGE to network */
+	if(my_mode()!=UMODE_INVISIBLE) {
+		m = qcs_newmsg();
+		m->msg = QCS_MSG_MODE_CHANGE;
+		m->umode = net_qcs_mode(my_mode());
+		qcs_msgset(m, QCS_SRC, my_nickname());
+		net_send(m);
+		qcs_deletemsg(m);
+	}
+}
+
+static void
+net_prefs_net_settings_changed_cb(const gchar * prefs_name)
+{
+	if(app_status()==APP_RUNNING) {
+		gboolean do_reconnect;
+
+		if(!strcmp(prefs_name, PREFS_NET_TYPE))
+			do_reconnect = 1;
+		else if(!strcmp(prefs_name, PREFS_NET_PORT))
+			do_reconnect = 1;
+		else if(!strcmp(prefs_name, PREFS_NET_USE_MULTICAST))
+			do_reconnect = prefs_int(PREFS_NET_TYPE)==NET_TYPE_VYPRESS;
+		else if(!strcmp(prefs_name, PREFS_NET_MULTICAST_ADDR))
+			do_reconnect =
+				prefs_int(PREFS_NET_TYPE)==NET_TYPE_VYPRESS
+				&& prefs_bool(PREFS_NET_USE_MULTICAST);
+		else if(!strcmp(prefs_name, PREFS_NET_BROADCAST_MASK))
+			do_reconnect =
+				prefs_int(PREFS_NET_TYPE)!=NET_TYPE_VYPRESS
+				|| !prefs_bool(PREFS_NET_USE_MULTICAST);
+		else
+			do_reconnect = 0;
+					
+		if(do_reconnect) {
+			net_disconnect();
+			net_connect();
+		}
+	}
+}
+
+static void
+net_prefs_net_is_configured_changed_cb(const gchar * prefs_name)
+{
+	if(prefs_bool(PREFS_NET_IS_CONFIGURED)
+			&& !net_connected()
+			&& app_status()==APP_RUNNING)
+		net_connect();
+}
+
+static void
+net_register_prefs()
+{
+	prefs_register(PREFS_NET_TYPE,		PREFS_TYPE_UINT,
+		_("Network type"), net_prefs_type_validator, NULL);
+	prefs_register(PREFS_NET_PORT,		PREFS_TYPE_UINT,
+		_("Network port"), net_prefs_port_validator, NULL);
+	prefs_register(PREFS_NET_IS_CONFIGURED,	PREFS_TYPE_BOOL,
+		_("Network is configured"), NULL, NULL);
+	prefs_register(PREFS_NET_BROADCAST_MASK, PREFS_TYPE_UINT,
+		_("Network broadcast mask"), NULL, NULL);
+	prefs_register(PREFS_NET_USE_MULTICAST, PREFS_TYPE_BOOL,
+		_("Use multicast networking"), NULL, NULL);
+	prefs_register(PREFS_NET_MULTICAST_ADDR, PREFS_TYPE_UINT,
+		_("Network multicast address"), NULL, NULL);
+	prefs_register(PREFS_NET_VERBOSE,	PREFS_TYPE_BOOL, 
+		_("Verbosely report network events"), NULL, NULL);
+	prefs_register(PREFS_NET_CHANNEL_NOTIFY,PREFS_TYPE_BOOL,
+		_("Notify channel users on join/leave"), NULL, NULL);
+	prefs_register(PREFS_NET_IGNORE_MASS_MSG,PREFS_TYPE_BOOL,
+		_("Ignore mass messages"), NULL, NULL);
+	prefs_register(PREFS_NET_ENCODING,	PREFS_TYPE_STR,
+		_("Network charset encoding"), net_prefs_encoding_validator, NULL);
+	prefs_register(PREFS_NET_SECONDARY_ENCODING,	PREFS_TYPE_STR,
+		_("Secondary network charset encoding"), net_prefs_encoding_validator, NULL);
+	prefs_register(PREFS_NET_CHARSET_CHOICE,	PREFS_TYPE_BOOL, 
+		_("Send messages in primary charset"), NULL, NULL);
+	prefs_register(PREFS_NET_REPLY_INFO_REQ,PREFS_TYPE_BOOL, 
+		_("Reply to user information requests"), NULL, NULL);
+	prefs_register(PREFS_NET_MOTD,		PREFS_TYPE_STR, 
+		_("User information text"), NULL, NULL);
+	prefs_register(PREFS_NET_MOTD_WHEN_AWAY,PREFS_TYPE_STR,
+		_("User information text when away"), NULL, NULL);
+	prefs_register(PREFS_NET_IGNORED_USERS, PREFS_TYPE_LIST,
+		_("Ignored users"), NULL, NULL);
+
+	prefs_add_notifier(PREFS_MAIN_NICKNAME, (GHookFunc)net_prefs_main_nickname_changed_cb);
+	prefs_add_notifier(PREFS_MAIN_MODE, (GHookFunc)net_prefs_main_mode_changed_cb);
+
+	prefs_add_notifier(PREFS_NET_PORT, (GHookFunc)net_prefs_net_settings_changed_cb);
+	prefs_add_notifier(PREFS_NET_TYPE, (GHookFunc)net_prefs_net_settings_changed_cb);
+	prefs_add_notifier(PREFS_NET_BROADCAST_MASK, (GHookFunc)net_prefs_net_settings_changed_cb);
+	prefs_add_notifier(PREFS_NET_MULTICAST_ADDR, (GHookFunc)net_prefs_net_settings_changed_cb);
+	prefs_add_notifier(PREFS_NET_USE_MULTICAST, (GHookFunc)net_prefs_net_settings_changed_cb);
+
+	prefs_add_notifier(PREFS_NET_IS_CONFIGURED, (GHookFunc)net_prefs_net_is_configured_changed_cb);
+}
+
+static void
+net_preset_prefs()
+{
+	/* set default values */
+	prefs_set(PREFS_NET_CHANNEL_NOTIFY, TRUE);
+	prefs_set(PREFS_NET_ENCODING, NET_DEFAULT_CHARSET);
+	prefs_set(PREFS_NET_SECONDARY_ENCODING, NET_DEFAULT_CHARSET);
+	prefs_set(PREFS_NET_CHARSET_CHOICE, TRUE);
+	prefs_set(PREFS_NET_REPLY_INFO_REQ, TRUE);
+	prefs_set(PREFS_NET_MOTD_WHEN_AWAY, _("User is away"));
+	prefs_set(PREFS_NET_BROADCAST_MASK, 0xffffffff);	/* 255.255.255.255 */
+	prefs_set(PREFS_NET_MULTICAST_ADDR, 0xe3000002);	/* 227.0.0.2 */
+}
+
+static void
+net_event_cb(enum app_event_enum e, gpointer p, int i)
+{
+	switch(e) {
+	case EVENT_MAIN_INIT:
+		net = NULL;
+		net_event_source = 0;
+		old_nickname = g_string_new(NULL);
+		break;
+
+	case EVENT_MAIN_REGISTER_PREFS:
+		net_register_prefs();
+		break;
+
+	case EVENT_MAIN_PRESET_PREFS:
+		net_preset_prefs();
+		break;
+
+	case EVENT_MAIN_START:
+		/* gui_netselect_dlg should popup it's dialog
+		 * if the network is not configured
+		 */
+		if(prefs_bool(PREFS_NET_IS_CONFIGURED))
+			net_connect();
+		break;
+
+	case EVENT_MAIN_PRECLOSE:
+		net_disconnect();
+		break;
+
+	case EVENT_MAIN_CLOSE:
+		g_string_free(old_nickname, TRUE);
+		old_nickname = NULL;
+		break;
+
+	case EVENT_SESSION_OPENED:
+	case EVENT_SESSION_CLOSED:
+		net_handle_session_open_close(
+			(sess_id)p,
+			e==EVENT_SESSION_OPENED);
+		break;
+
+	case EVENT_SESSION_TOPIC_ENTER:
+		if(sess_type(EVENT_V(p, 0))==SESSTYPE_CHANNEL)
+			handle_channel_topic_enter(EVENT_V(p,0), EVENT_V(p,1));
+		break;
+
+	case EVENT_CMDPROC_SESSION_TEXT:
+		net_handle_my_text((const char *)p, i);
+		break;
+	case EVENT_MESSAGE_SEND:
+		net_send_message_to(EVENT_V(p,0), (const char *)EVENT_V(p,1),(gboolean)EVENT_V(p,2));
+		break;
+	case EVENT_USER_NET_UPDATE_REQ:
+		net_send_refresh_req();
+		break;
+	case EVENT_IFACE_USER_INFO_REQ:
+		net_send_info_req(p);
+		break;
+	case EVENT_IFACE_USER_BEEP_REQ:
+		net_send_beep(p);
+		break;
+	case EVENT_IFACE_REQUEST_NET_CHANNELS:
+		net_send_chan_req();
+		break;
+	case EVENT_IFACE_ACTIVE_CHANGE:
+		net_send_active_change((gboolean)i);
+		break;
+	default:
+		break;	/* nothing else */
+	}
+}
+
+static gboolean
+net_connect()
+{
+	GIOChannel * channel;
+	int rx_socket;
+	enum net_type_enum type = prefs_int(PREFS_NET_TYPE);
+	unsigned short port = prefs_int(PREFS_NET_PORT);
+
+	g_assert(net==NULL);
+
+	/* check network type num */
+	if(type>=NET_TYPE_NUM) {
+		log_error(_(LOG_NET), ("invalid network type specified: falling back to QuickChat"));
+		type = NET_TYPE_QCHAT;
+	}
+
+	/* notify everyone that we're about to connect to the network */
+	raise_event(EVENT_NET_PRECONNECT, 0, 0);
+
+	net_type = type;
+
+	/* do the real connecting */
+	if(type==QCS_PROTO_VYPRESS) {
+		int use_multicast = prefs_bool(PREFS_NET_USE_MULTICAST);
+		net = qcs_open(
+			QCS_PROTO_VYPRESS,
+			use_multicast ? QCS_PROTO_OPT_MULTICAST: 0,
+			use_multicast
+				? prefs_int(PREFS_NET_MULTICAST_ADDR)
+				: prefs_int(PREFS_NET_BROADCAST_MASK),
+			port);
+	} else {
+		net = qcs_open(QCS_PROTO_QCHAT, 0, prefs_int(PREFS_NET_BROADCAST_MASK), port);
+	}
+
+	/* check for errors */
+	if(!net) {
+		log_ferror(_(LOG_NET), g_strdup_printf(
+			_("failed to connect to %s network on port %hd: %s"),
+				net_name_of_type(type), port, strerror(errno)));
+		log_error(_(LOG_NET),
+			_("check if there are any programs running on the same port"
+				" and your firewall settings"));
+		return FALSE;
+	}
+
+	/* install glib event handler on socket */
+	qcs_rxsocket(net, &rx_socket);
+	channel = g_io_channel_unix_new(rx_socket);
+	net_event_source = g_io_add_watch(
+			channel,
+			G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+			net_io_func, 0);
+	g_io_channel_unref(channel);
+
+	log_fevent(_(LOG_NET), g_strdup_printf(
+		_("connected to %s network on port %hd"), net_name_of_type(type), port));
+
+	/* notify that we've connected */
+	raise_event(EVENT_NET_CONNECTED, 0,0);
+
+	return TRUE;
+}
+
+static void
+net_disconnect()
+{
+	if(net) {
+		/* notify everyone of our evil intentions */
+		raise_event(EVENT_NET_PREDISCONNECT, 0,0);
+
+		/* remove io_chan */
+		g_source_remove(net_event_source);
+		net_event_source = 0;
+
+		/* close link */
+		qcs_close(net);
+		net = NULL;
+
+		raise_event(EVENT_NET_DISCONNECTED, 0,0);
+	}
+}
+
+/** exported routines
+  *************************/
+void net_register()
+{
+	register_event_cb(
+		net_event_cb,
+		EVENT_MAIN | EVENT_CMDPROC | EVENT_IFACE
+		| EVENT_SESSION | EVENT_MESSAGE | EVENT_USER);
+}
+
+gboolean net_connected()
+{
+	return net!=NULL;
+}
+
+const gchar *
+net_name_of_type(enum net_type_enum t)
+{
+	switch(t) {
+	case NET_TYPE_QCHAT:	return "quickChat";
+	case NET_TYPE_VYPRESS:	return "Vypress Chat";
+	default:
+		break;	/* nothing else */
+	}
+	return "(invalid network type)";
 }
diff -NrU2 vqcc-gtk-0.5/src/net.h vqcc-gtk-0.5.1-shaman5/src/net.h
--- vqcc-gtk-0.5/src/net.h	2004-12-17 05:04:29.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/net.h	2005-03-30 16:27:11.000000000 +0400
@@ -34,4 +34,6 @@
 #define PREFS_NET_IGNORE_MASS_MSG	"net/ignore_mass_msg"
 #define PREFS_NET_ENCODING		"net/encoding"
+#define PREFS_NET_SECONDARY_ENCODING		"net/secondary_encoding"
+#define PREFS_NET_CHARSET_CHOICE		"net/charset_choice"
 #define PREFS_NET_REPLY_INFO_REQ	"net/reply_info_req"
 #define PREFS_NET_MOTD			"net/motd"
@@ -56,3 +58,2 @@
 
 #endif /* #ifndef NET_H__ */
-
diff -NrU2 vqcc-gtk-0.5/src/user.c vqcc-gtk-0.5.1-shaman5/src/user.c
--- vqcc-gtk-0.5/src/user.c	2004-12-21 18:11:37.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/user.c	2005-06-28 20:50:38.000000000 +0400
@@ -36,4 +36,5 @@
 	gboolean is_active;	/* if user is active (emm.. watching) */
 	time_t last_time_active;/* this can be 0, if the user never changed his 'active' state */
+	unsigned long src_ip;	/* IP address of message source */
 	gboolean replied;	/* if the user has replied to refresh req */
 }
@@ -123,5 +124,5 @@
  */
 static gpointer
-add_user(const gchar * name, enum user_mode_enum mode)
+add_user(const gchar * name, enum user_mode_enum mode,const unsigned long * src_ip)
 {
 	user_info_t * u;
@@ -134,4 +135,5 @@
 	u = g_malloc(sizeof(user_info_t));
 	u->name = g_string_new(name);
+	u->src_ip = src_ip;
 	u->mode = mode;
 	u->is_active = TRUE;
@@ -347,5 +349,5 @@
 
 	case EVENT_NET_NEW_USER:
-		user = add_user(EVENT_V(p, 0), (enum user_mode_enum)EVENT_V(p, 1));
+		user = add_user(EVENT_V(p, 0), (enum user_mode_enum)EVENT_V(p, 1),EVENT_V(p, 3));
 		if(!EVENT_V(p, 2))
 			update_user_last_time_active(user);
@@ -456,4 +458,12 @@
 }
 
+const unsigned long *
+user_ip_of(gconstpointer u)
+{
+	//g_assert(u);
+	if(u==NULL) return 0;
+	return PUSER_INFO_T(u)->src_ip;
+}
+
 time_t
 user_last_time_active(gpointer user)
@@ -487,4 +497,2 @@
 	return name;
 }
-
-
diff -NrU2 vqcc-gtk-0.5/src/util.h vqcc-gtk-0.5.1-shaman5/src/util.h
--- vqcc-gtk-0.5/src/util.h	2004-12-24 06:16:04.000000000 +0300
+++ vqcc-gtk-0.5.1-shaman5/src/util.h	2005-04-12 02:30:53.000000000 +0400
@@ -23,4 +23,16 @@
 #define UTIL_H__
 
+enum user_list_column_enum {
+	COLUMN_ICON,
+	COLUMN_NICKNAME,
+	COLUMN_USER_PTR,
+	COLUMN_SELECTED,
+	COLUMN_NUM
+};
+
+
+
+//struct _ulist* Ulist;
+	
 /* list functions
  */
@@ -45,3 +57,2 @@
 
 #endif	/* #ifndef UTIL_H__ */
-
