summary refs log tree commit diff stats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/cfgfiles.c107
-rw-r--r--src/common/chanopt.c13
-rw-r--r--src/common/common.vcxproj157
-rw-r--r--src/common/common.vcxproj.filters194
-rw-r--r--src/common/common.vcxproj.user3
-rw-r--r--src/common/ctcp.c22
-rw-r--r--src/common/dcc.c22
-rw-r--r--src/common/identd.c100
-rw-r--r--src/common/identd.h1
-rw-r--r--src/common/ignore.c5
-rw-r--r--src/common/inbound.c7
-rw-r--r--src/common/inet.h4
-rw-r--r--src/common/makefile.mak45
-rw-r--r--src/common/modes.c10
-rw-r--r--src/common/msproxy.c5
-rw-r--r--src/common/network.c5
-rw-r--r--src/common/notify.c5
-rw-r--r--src/common/outbound.c110
-rw-r--r--src/common/plugin-timer.c10
-rw-r--r--src/common/plugin.c273
-rw-r--r--src/common/plugin.h15
-rw-r--r--src/common/proto-irc.c15
-rw-r--r--src/common/server.c75
-rw-r--r--src/common/servlist.c13
-rw-r--r--src/common/ssl.c2
-rw-r--r--src/common/text.c104
-rw-r--r--src/common/text.h3
-rw-r--r--src/common/thread.c33
-rw-r--r--src/common/thread.h10
-rw-r--r--src/common/url.c8
-rw-r--r--src/common/util.c195
-rw-r--r--src/common/util.h9
-rw-r--r--src/common/xchat-plugin.h47
-rw-r--r--src/common/xchat.c86
-rw-r--r--src/common/xchat.h33
35 files changed, 1540 insertions, 206 deletions
diff --git a/src/common/cfgfiles.c b/src/common/cfgfiles.c
index 83f50e37..111234e9 100644
--- a/src/common/cfgfiles.c
+++ b/src/common/cfgfiles.c
@@ -17,7 +17,6 @@
  */
 
 #include <fcntl.h>
-#include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -31,12 +30,15 @@
 #include "text.h"
 #include "xchatc.h"
 
-#ifdef WIN32
-#define XCHAT_DIR "X-Chat 2"
-#else
+#ifndef WIN32
+#include <unistd.h>
 #define XCHAT_DIR ".xchat2"
 #endif
+
 #define DEF_FONT "Monospace 9"
+#ifdef WIN32
+#define DEF_FONT_ALTER "Arial Unicode MS,Lucida Sans Unicode"
+#endif
 
 void
 list_addentry (GSList ** list, char *cmd, char *name)
@@ -82,11 +84,11 @@ list_load_from_data (GSList ** list, char *ibuf, int size)
 	{
 		if (*buf != '#')
 		{
-			if (!strncasecmp (buf, "NAME ", 5))
+			if (!g_ascii_strncasecmp (buf, "NAME ", 5))
 			{
 				safe_strcpy (name, buf + 5, sizeof (name));
 			}
-			else if (!strncasecmp (buf, "CMD ", 4))
+			else if (!g_ascii_strncasecmp (buf, "CMD ", 4))
 			{
 				safe_strcpy (cmd, buf + 4, sizeof (cmd));
 				if (*name)
@@ -152,7 +154,7 @@ list_delentry (GSList ** list, char *name)
 	while (alist)
 	{
 		pop = (struct popup *) alist->data;
-		if (!strcasecmp (name, pop->name))
+		if (!g_ascii_strcasecmp (name, pop->name))
 		{
 			*list = g_slist_remove (*list, pop);
 			free (pop);
@@ -166,9 +168,13 @@ list_delentry (GSList ** list, char *name)
 char *
 cfg_get_str (char *cfg, char *var, char *dest, int dest_len)
 {
+	char buffer[128];	/* should be plenty for a variable name */
+
+	sprintf (buffer, "%s ", var);	/* add one space, this way it works against var - var2 checks too */
+
 	while (1)
 	{
-		if (!strncasecmp (var, cfg, strlen (var)))
+		if (!g_ascii_strncasecmp (buffer, cfg, strlen (var) + 1))
 		{
 			char *value, t;
 			cfg += strlen (var);
@@ -308,12 +314,19 @@ get_xdir_fs (void)
 {
 	if (!xdir_fs)
 	{
-		char out[256];
+		if (portable_mode ())
+		{
+			xdir_fs = ".\\config";
+		}
+		else
+		{
+			char out[256];
 
-		if (!get_reg_str ("Software\\Microsoft\\Windows\\CurrentVersion\\"
-				"Explorer\\Shell Folders", "AppData", out, sizeof (out)))
-			return "./config";
-		xdir_fs = g_strdup_printf ("%s\\" XCHAT_DIR, out);
+			if (!get_reg_str ("Software\\Microsoft\\Windows\\CurrentVersion\\"
+					"Explorer\\Shell Folders", "AppData", out, sizeof (out)))
+				return "./config";
+			xdir_fs = g_strdup_printf ("%s\\" "X-Chat 2", out);
+		}
 	}
 	return xdir_fs;
 }
@@ -393,7 +406,9 @@ const struct prefs vars[] = {
 	{"dcc_blocksize", P_OFFINT (dcc_blocksize), TYPE_INT},
 	{"dcc_completed_dir", P_OFFSET (dcc_completed_dir), TYPE_STR},
 	{"dcc_dir", P_OFFSET (dccdir), TYPE_STR},
+#ifndef WIN32
 	{"dcc_fast_send", P_OFFINT (fastdccsend), TYPE_BOOL},
+#endif
 	{"dcc_global_max_get_cps", P_OFFINT (dcc_global_max_get_cps), TYPE_INT},
 	{"dcc_global_max_send_cps", P_OFFINT (dcc_global_max_send_cps), TYPE_INT},
 	{"dcc_ip", P_OFFSET (dcc_ip_str), TYPE_STR},
@@ -429,9 +444,14 @@ const struct prefs vars[] = {
 	{"gui_input_style", P_OFFINT (style_inputbox), TYPE_BOOL},
 	{"gui_join_dialog", P_OFFINT (gui_join_dialog), TYPE_BOOL},
 	{"gui_lagometer", P_OFFINT (lagometer), TYPE_INT},
+	{"gui_license", P_OFFSET (gui_license), TYPE_STR},
 	{"gui_mode_buttons", P_OFFINT (chanmodebuttons), TYPE_BOOL},
+#ifdef WIN32
+	{"gui_one_instance", P_OFFINT (gui_one_instance), TYPE_BOOL},
+#endif
 	{"gui_pane_left_size", P_OFFINT (gui_pane_left_size), TYPE_INT},
 	{"gui_pane_right_size", P_OFFINT (gui_pane_right_size), TYPE_INT},
+	{"gui_pane_right_size_min", P_OFFINT (gui_pane_right_size_min), TYPE_INT},
 	{"gui_quit_dialog", P_OFFINT (gui_quit_dialog), TYPE_BOOL},
 	{"gui_slist_fav", P_OFFINT (slist_fav), TYPE_INT},
 	{"gui_slist_select", P_OFFINT (slist_select), TYPE_INT},
@@ -536,6 +556,9 @@ const struct prefs vars[] = {
 
 	{"tab_chans", P_OFFINT (tabchannels), TYPE_BOOL},
 	{"tab_dialogs", P_OFFINT (privmsgtab), TYPE_BOOL},
+#ifdef WIN32
+	{"tab_icons", P_OFFINT (tab_icons), TYPE_BOOL},
+#endif
 	{"tab_layout", P_OFFINT (tab_layout), TYPE_INT},
 	{"tab_new_to_front", P_OFFINT (newtabstofront), TYPE_INT},
 	{"tab_notices", P_OFFINT (notices_tabs), TYPE_BOOL},
@@ -546,16 +569,35 @@ const struct prefs vars[] = {
 	{"tab_sort", P_OFFINT (tab_sort), TYPE_BOOL},
 	{"tab_trunc", P_OFFINT (truncchans), TYPE_INT},
 	{"tab_utils", P_OFFINT (windows_as_tabs), TYPE_BOOL},
+#ifdef WIN32
+	{"tab_xp", P_OFFINT (tab_xp), TYPE_BOOL},
+#endif
 
+	{"text_auto_copy_color", P_OFFINT (autocopy_color), TYPE_BOOL},	
+	{"text_auto_copy_stamp", P_OFFINT (autocopy_stamp), TYPE_BOOL},
+	{"text_auto_copy_text", P_OFFINT (autocopy_text), TYPE_BOOL},
 	{"text_background", P_OFFSET (background), TYPE_STR},
 	{"text_color_nicks", P_OFFINT (colorednicks), TYPE_BOOL},
+#ifdef WIN32
+	{"text_emoticons", P_OFFINT (emoticons), TYPE_BOOL},
+#endif
 	{"text_font", P_OFFSET (font_normal), TYPE_STR},
+#ifdef WIN32
+	{"text_font_main", P_OFFSET (font_main), TYPE_STR},
+	{"text_font_alternative", P_OFFSET (font_alternative), TYPE_STR},
+#endif
 	{"text_indent", P_OFFINT (indent_nicks), TYPE_BOOL},
 	{"text_max_indent", P_OFFINT (max_auto_indent), TYPE_INT},
 	{"text_max_lines", P_OFFINT (max_lines), TYPE_INT},
 	{"text_replay", P_OFFINT (text_replay), TYPE_BOOL},
+	{"text_search_case_match", P_OFFINT (text_search_case_match), TYPE_BOOL},
+	{"text_search_backward", P_OFFINT (text_search_backward), TYPE_BOOL},
+	{"text_search_highlight_all", P_OFFINT (text_search_highlight_all), TYPE_BOOL},
+	{"text_search_follow", P_OFFINT (text_search_follow), TYPE_BOOL},
+	{"text_search_regexp", P_OFFINT (text_search_regexp), TYPE_BOOL},
 	{"text_show_marker", P_OFFINT (show_marker), TYPE_BOOL},
 	{"text_show_sep", P_OFFINT (show_separator), TYPE_BOOL},
+	{"text_spell_langs", P_OFFSET (spell_langs), TYPE_STR},
 	{"text_stripcolor", P_OFFINT (stripcolor), TYPE_BOOL},
 	{"text_thin_sep", P_OFFINT (thin_separator), TYPE_BOOL},
 	{"text_tint_blue", P_OFFINT (tint_blue), TYPE_INT},
@@ -601,9 +643,11 @@ load_config (void)
 	if (!username)
 		username = "root";
 
-	realname = g_get_real_name ();
+	/* We hid Real name from the Network List, so don't use the user's name unnoticeably */
+	/* realname = g_get_real_name ();
 	if ((realname && realname[0] == 0) || !realname)
-		realname = username;
+		realname = username; */
+	realname = "realname";
 
 	username = convert_with_fallback (username, "username");
 	realname = convert_with_fallback (realname, "realname");
@@ -626,13 +670,16 @@ load_config (void)
 	prefs.indent_nicks = 1;
 	prefs.thin_separator = 1;
 	prefs._tabs_position = 2; /* 2 = left */
+#ifndef WIN32
 	prefs.fastdccsend = 1;
+#endif
 	prefs.wordwrap = 1;
 	prefs.autosave = 1;
 	prefs.autodialog = 1;
 	prefs.gui_input_spell = 1;
 	prefs.autoreconnect = 1;
 	prefs.recon_delay = 10;
+	prefs.autocopy_text = 1;
 	prefs.text_replay = 1;
 	prefs.tabchannels = 1;
 	prefs.tab_layout = 2;	/* 0=Tabs 1=Reserved 2=Tree */
@@ -676,6 +723,7 @@ load_config (void)
 	prefs.gui_tray = 1;
 	prefs.gui_pane_left_size = 100;
 	prefs.gui_pane_right_size = 100;
+	prefs.gui_pane_right_size_min = 80;
 	prefs.mainwindow_save = 1;
 	prefs.bantype = 2;
 	prefs.input_balloon_time = 20;
@@ -684,9 +732,12 @@ load_config (void)
 	prefs.autodccsend = 2;	/* browse mode */
 	prefs.url_grabber = 1;
 	prefs.url_grabber_limit = 0; /* 0 means unlimited for backcompat */
+	prefs.text_search_follow = 1;
 #ifdef WIN32
 	prefs.identd = 1;
 #endif
+	strcpy (prefs.gui_license, "");
+	strcpy (prefs.spell_langs, g_getenv ("LC_ALL") ? g_getenv ("LC_ALL") : "en_US");
 	strcpy (prefs.stamp_format, "[%H:%M] ");
 	strcpy (prefs.timestamp_log_format, "%b %d %H:%M:%S ");
 	strcpy (prefs.logmask, "%n-%c.log");
@@ -719,6 +770,10 @@ load_config (void)
 	strcpy (prefs.quitreason, _("Leaving"));
 	strcpy (prefs.partreason, prefs.quitreason);
 	strcpy (prefs.font_normal, DEF_FONT);
+#ifdef WIN32
+	strcpy (prefs.font_main, DEF_FONT);
+	strcpy (prefs.font_alternative, DEF_FONT_ALTER);
+#endif
 	strcpy (prefs.dnsprogram, "host");
 	strcpy (prefs.irc_no_hilight, "NickServ,ChanServ");
 
@@ -945,7 +1000,7 @@ cfg_get_bool (char *var)
 
 	do
 	{
-		if (!strcasecmp (var, vars[i].name))
+		if (!g_ascii_strcasecmp (var, vars[i].name))
 		{
 			return *((int *) &prefs + vars[i].offset);
 		}
@@ -968,27 +1023,27 @@ cmd_set (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	int idx = 2;
 	char *var, *val;
 
-	if (strcasecmp (word[2], "-e") == 0)
+	if (g_ascii_strcasecmp (word[2], "-e") == 0)
 	{
 		idx++;
 		erase = TRUE;
 	}
 
 	/* turn a bit OFF */
-	if (strcasecmp (word[idx], "-off") == 0)
+	if (g_ascii_strcasecmp (word[idx], "-off") == 0)
 	{
 		idx++;
 		off = TRUE;
 	}
 
 	/* turn a bit ON */
-	if (strcasecmp (word[idx], "-or") == 0 || strcasecmp (word[idx], "-on") == 0)
+	if (g_ascii_strcasecmp (word[idx], "-or") == 0 || g_ascii_strcasecmp (word[idx], "-on") == 0)
 	{
 		idx++;
 		or = TRUE;
 	}
 
-	if (strcasecmp (word[idx], "-quiet") == 0)
+	if (g_ascii_strcasecmp (word[idx], "-quiet") == 0)
 	{
 		idx++;
 		quiet = TRUE;
@@ -1014,7 +1069,7 @@ cmd_set (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 		if (wild)
 			found = !match (var, vars[i].name);
 		else
-			found = strcasecmp (var, vars[i].name);
+			found = g_ascii_strcasecmp (var, vars[i].name);
 
 		if (found == 0)
 		{
@@ -1043,9 +1098,9 @@ cmd_set (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 							*((int *) &prefs + vars[i].offset) = 1;
 						else
 							*((int *) &prefs + vars[i].offset) = 0;
-						if (!strcasecmp (val, "YES") || !strcasecmp (val, "ON"))
+						if (!g_ascii_strcasecmp (val, "YES") || !g_ascii_strcasecmp (val, "ON"))
 							*((int *) &prefs + vars[i].offset) = 1;
-						if (!strcasecmp (val, "NO") || !strcasecmp (val, "OFF"))
+						if (!g_ascii_strcasecmp (val, "NO") || !g_ascii_strcasecmp (val, "OFF"))
 							*((int *) &prefs + vars[i].offset) = 0;
 					} else
 					{
@@ -1071,7 +1126,13 @@ cmd_set (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	while (vars[i].name);
 
 	if (!finds && !quiet)
+	{
 		PrintText (sess, "No such variable.\n");
+	}
+	else if (prefs.autosave && !save_config ())
+	{
+		PrintText (sess, "Error saving changes to disk.\n");
+	}
 
 	return TRUE;
 }
diff --git a/src/common/chanopt.c b/src/common/chanopt.c
index a4fd8faa..198ebe6c 100644
--- a/src/common/chanopt.c
+++ b/src/common/chanopt.c
@@ -3,12 +3,15 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat.h"
 
 #include "cfgfiles.h"
@@ -81,9 +84,9 @@ chanopt_command (session *sess, char *tbuf, char *word[], char *word_eol[])
 
 	if (word[offset][0])
 	{
-		if (!strcasecmp (word[offset], "ON"))
+		if (!g_ascii_strcasecmp (word[offset], "ON"))
 			newval = 1;
-		else if (!strcasecmp (word[offset], "OFF"))
+		else if (!g_ascii_strcasecmp (word[offset], "OFF"))
 			newval = 0;
 		else if (word[offset][0] == 'u')
 			newval = SET_DEFAULT;
@@ -183,8 +186,8 @@ chanopt_find (char *network, char *channel, gboolean add_new)
 	for (list = chanopt_list; list; list = list->next)
 	{
 		co = list->data;
-		if (!strcasecmp (co->channel, channel) &&
-			 !strcasecmp (co->network, network))
+		if (!g_ascii_strcasecmp (co->channel, channel) &&
+			 !g_ascii_strcasecmp (co->network, network))
 			return co;
 	}
 
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
new file mode 100644
index 00000000..4e95c929
--- /dev/null
+++ b/src/common/common.vcxproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="..\..\config.h" />

+    <ClInclude Include="cfgfiles.h" />

+    <ClInclude Include="chanopt.h" />

+    <ClInclude Include="ctcp.h" />

+    <ClInclude Include="dcc.h" />

+    <ClInclude Include="fe.h" />

+    <ClInclude Include="history.h" />

+    <ClInclude Include="identd.h" />

+    <ClInclude Include="ignore.h" />

+    <ClInclude Include="inbound.h" />

+    <ClInclude Include="inet.h" />

+    <ClInclude Include="modes.h" />

+    <ClInclude Include="msproxy.h" />

+    <ClInclude Include="network.h" />

+    <ClInclude Include="notify.h" />

+    <ClInclude Include="outbound.h" />

+    <ClInclude Include="plugin-timer.h" />

+    <ClInclude Include="plugin.h" />

+    <ClInclude Include="proto-irc.h" />

+    <ClInclude Include="server.h" />

+    <ClInclude Include="servlist.h" />

+    <ClInclude Include="ssl.h" />

+    <ClInclude Include="text.h" />

+    <ClInclude Include="textenums.h" />

+    <ClInclude Include="textevents.h" />

+    <ClInclude Include="thread.h" />

+    <ClInclude Include="tree.h" />

+    <ClInclude Include="url.h" />

+    <ClInclude Include="userlist.h" />

+    <ClInclude Include="util.h" />

+    <ClInclude Include="xchat-plugin.h" />

+    <ClInclude Include="xchat.h" />

+    <ClInclude Include="xchatc.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="cfgfiles.c" />

+    <ClCompile Include="chanopt.c" />

+    <ClCompile Include="ctcp.c" />

+    <ClCompile Include="dcc.c" />

+    <ClCompile Include="history.c" />

+    <ClCompile Include="identd.c" />

+    <ClCompile Include="ignore.c" />

+    <ClCompile Include="inbound.c" />

+    <ClCompile Include="modes.c" />

+    <ClCompile Include="msproxy.c" />

+    <ClCompile Include="network.c" />

+    <ClCompile Include="notify.c" />

+    <ClCompile Include="outbound.c" />

+    <ClCompile Include="plugin-timer.c" />

+    <ClCompile Include="plugin.c" />

+    <ClCompile Include="proto-irc.c" />

+    <ClCompile Include="server.c" />

+    <ClCompile Include="servlist.c" />

+    <ClCompile Include="ssl.c" />

+    <ClCompile Include="text.c" />

+    <ClCompile Include="thread.c" />

+    <ClCompile Include="tree.c" />

+    <ClCompile Include="url.c" />

+    <ClCompile Include="userlist.c" />

+    <ClCompile Include="util.c" />

+    <ClCompile Include="xchat.c" />

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{87554B59-006C-4D94-9714-897B27067BA3}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>common</RootNamespace>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>MultiByte</CharacterSet>

+    <PlatformToolset>WDK7</PlatformToolset>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>StaticLibrary</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>MultiByte</CharacterSet>

+    <PlatformToolset>WDK7</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+    <Import Project="..\..\win32\xchat.props" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+    <Import Project="..\..\win32\xchat.props" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <OutDir>$(SolutionDir)build\$(PlatformName)\bin</OutDir>

+    <IntDir>$(SolutionDir)build\$(PlatformName)\obj\$(ProjectName)</IntDir>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <OutDir>$(SolutionDir)build\$(PlatformName)\bin</OutDir>

+    <IntDir>$(SolutionDir)build\$(PlatformName)\obj\$(ProjectName)</IntDir>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <WarningLevel>Level1</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+    </ClCompile>

+    <Link>

+      <SubSystem>Windows</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <WarningLevel>Level1</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;_WIN64;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+    </ClCompile>

+    <Link>

+      <SubSystem>Windows</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
new file mode 100644
index 00000000..afb66e63
--- /dev/null
+++ b/src/common/common.vcxproj.filters
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>

+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="cfgfiles.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="chanopt.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ctcp.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="dcc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="fe.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="history.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="identd.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ignore.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="inbound.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="inet.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="modes.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="msproxy.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="network.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="notify.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="outbound.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="plugin.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="plugin-timer.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="proto-irc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="server.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="servlist.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ssl.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="text.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="textenums.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="textevents.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="thread.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="tree.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="url.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="userlist.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="util.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="xchat.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="xchatc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="xchat-plugin.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="..\..\config.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="cfgfiles.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="chanopt.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ctcp.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="dcc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="history.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="identd.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ignore.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="inbound.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="modes.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="msproxy.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="network.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="notify.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="outbound.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="plugin.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="plugin-timer.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="proto-irc.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="server.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="servlist.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ssl.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="text.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="thread.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="tree.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="url.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="userlist.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="util.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="xchat.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/common/common.vcxproj.user b/src/common/common.vcxproj.user
new file mode 100644
index 00000000..695b5c78
--- /dev/null
+++ b/src/common/common.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+</Project>
\ No newline at end of file
diff --git a/src/common/ctcp.c b/src/common/ctcp.c
index 574cda79..36952db7 100644
--- a/src/common/ctcp.c
+++ b/src/common/ctcp.c
@@ -18,9 +18,12 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdlib.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat.h"
 #include "cfgfiles.h"
 #include "util.h"
@@ -70,7 +73,7 @@ ctcp_check (session *sess, char *nick, char *word[], char *word_eol[],
 	while (list)
 	{
 		pop = (struct popup *) list->data;
-		if (!strcasecmp (ctcp, pop->name))
+		if (!g_ascii_strcasecmp (ctcp, pop->name))
 		{
 			ctcp_reply (sess, nick, word, word_eol, pop->cmd);
 			ret = 1;
@@ -94,7 +97,7 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
 			ctcp_offset = 3;
 
 	/* consider DCC to be different from other CTCPs */
-	if (!strncasecmp (msg, "DCC", 3))
+	if (!g_ascii_strncasecmp (msg, "DCC", 3))
 	{
 		/* but still let CTCP replies override it */
 		if (!ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset))
@@ -107,7 +110,7 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
 
 	/* consider ACTION to be different from other CTCPs. Check
       ignore as if it was a PRIV/CHAN. */
-	if (!strncasecmp (msg, "ACTION ", 7))
+	if (!g_ascii_strncasecmp (msg, "ACTION ", 7))
 	{
 		if (is_channel (serv, to))
 		{
@@ -132,16 +135,21 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
 	if (ignore_check (word[1], IG_CTCP))
 		return;
 
-	if (!strcasecmp (msg, "VERSION") && !prefs.hidever)
+	if (!g_ascii_strcasecmp (msg, "VERSION") && !prefs.hidever)
 	{
-		snprintf (outbuf, sizeof (outbuf), "VERSION xchat "PACKAGE_VERSION" %s",
+#ifdef WIN32
+		snprintf (outbuf, sizeof (outbuf), "VERSION XChat-WDK "PACKAGE_VERSION" [x%d] / %s",
+					 get_cpu_arch (), get_cpu_str ());
+#else
+		snprintf (outbuf, sizeof (outbuf), "VERSION XChat-WDK "PACKAGE_VERSION" %s",
 					 get_cpu_str ());
+#endif
 		serv->p_nctcp (serv, nick, outbuf);
 	}
 
 	if (!ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset))
 	{
-		if (!strncasecmp (msg, "SOUND", 5))
+		if (!g_ascii_strncasecmp (msg, "SOUND", 5))
 		{
 			po = strchr (word[5], '\001');
 			if (po)
diff --git a/src/common/dcc.c b/src/common/dcc.c
index 8f289342..4c8724d9 100644
--- a/src/common/dcc.c
+++ b/src/common/dcc.c
@@ -31,7 +31,6 @@
 #include <time.h>
 #include <errno.h>
 #include <sys/stat.h>
-#include <unistd.h>
 #include <fcntl.h>
 
 #define WANTSOCKET
@@ -41,6 +40,8 @@
 
 #ifdef WIN32
 #include <windows.h>
+#else
+#include <unistd.h>
 #endif
 
 #include "xchat.h"
@@ -57,6 +58,9 @@
 
 #ifdef USE_DCC64
 #define BIG_STR_TO_INT(x) strtoull(x,NULL,10)
+#ifdef WIN32
+#define stat _stat64
+#endif
 #else
 #define BIG_STR_TO_INT(x) strtoul(x,NULL,10)
 #endif
@@ -568,7 +572,7 @@ dcc_chat_line (struct DCC *dcc, char *line)
 
 	url_check_line (line, len);
 
-	if (line[0] == 1 && !strncasecmp (line + 1, "ACTION", 6))
+	if (line[0] == 1 && !g_ascii_strncasecmp (line + 1, "ACTION", 6))
 	{
 		po = strchr (line + 8, '\001');
 		if (po)
@@ -1936,9 +1940,9 @@ find_dcc (char *nick, char *file, int type)
 			{
 				if (!file[0])
 					return dcc;
-				if (!strcasecmp (file, file_part (dcc->file)))
+				if (!g_ascii_strcasecmp (file, file_part (dcc->file)))
 					return dcc;
-				if (!strcasecmp (file, dcc->file))
+				if (!g_ascii_strcasecmp (file, dcc->file))
 					return dcc;
 			}
 		}
@@ -1984,7 +1988,7 @@ is_same_file (struct DCC *dcc, struct DCC *new_dcc)
 
 	/* now handle case-insensitive Filesystems: HFS+, FAT */
 #ifdef WIN32
-#warning no win32 implementation - behaviour may be unreliable
+	/* warning no win32 implementation - behaviour may be unreliable */
 #else
 	/* this fstat() shouldn't really fail */
 	if ((dcc->fp == -1 ? stat (dcc->destfile_fs, &st_a) : fstat (dcc->fp, &st_a)) == -1)
@@ -2402,7 +2406,7 @@ handle_dcc (struct session *sess, char *nick, char *word[],
 	DCC_SIZE size;
 	int psend = 0;
 
-	if (!strcasecmp (type, "CHAT"))
+	if (!g_ascii_strcasecmp (type, "CHAT"))
 	{
 		port = atoi (word[8]);
 		addr = strtoul (word[7], NULL, 10);
@@ -2449,7 +2453,7 @@ handle_dcc (struct session *sess, char *nick, char *word[],
 		return;
 	}
 
-	if (!strcasecmp (type, "Resume"))
+	if (!g_ascii_strcasecmp (type, "Resume"))
 	{
 		port = atoi (word[7]);
 
@@ -2493,7 +2497,7 @@ handle_dcc (struct session *sess, char *nick, char *word[],
 		}
 		return;
 	}
-	if (!strcasecmp (type, "Accept"))
+	if (!g_ascii_strcasecmp (type, "Accept"))
 	{
 		port = atoi (word[7]);
 		dcc = find_dcc_from_port (port, TYPE_RECV);
@@ -2503,7 +2507,7 @@ handle_dcc (struct session *sess, char *nick, char *word[],
 		}
 		return;
 	}
-	if (!strcasecmp (type, "SEND"))
+	if (!g_ascii_strcasecmp (type, "SEND"))
 	{
 		char *file = file_part (word[6]);
 
diff --git a/src/common/identd.c b/src/common/identd.c
index 919282ea..430c7e8f 100644
--- a/src/common/identd.c
+++ b/src/common/identd.c
@@ -1,8 +1,13 @@
 /* simple identd server for xchat under win32 */
 
+#include "inet.h"
+#include "xchat.h"
+#include "xchatc.h"
 
 static int identd_is_running = FALSE;
-
+#ifdef USE_IPV6
+static int identd_ipv6_is_running = FALSE;
+#endif
 
 static int
 identd (char *username)
@@ -75,11 +80,102 @@ identd (char *username)
 	return 0;
 }
 
-static void
+#ifdef USE_IPV6
+static int
+identd_ipv6 (char *username)
+{
+	int sok, read_sok, len;
+	char *p;
+	char buf[256];
+	char outbuf[256];
+	char ipv6buf[60];
+	DWORD ipv6buflen = sizeof (ipv6buf);
+	struct sockaddr_in6 addr;
+
+	sok = socket (AF_INET6, SOCK_STREAM, 0);
+
+	if (sok == INVALID_SOCKET)
+	{
+		free (username);
+		return 0;
+	}
+
+	len = 1;
+	setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
+
+	memset (&addr, 0, sizeof (addr));
+	addr.sin6_family = AF_INET6;
+	addr.sin6_port = htons (113);
+
+	if (bind (sok, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
+	{
+		closesocket (sok);
+		free (username);
+		return 0;
+	}
+
+	if (listen (sok, 1) == SOCKET_ERROR)
+	{
+		closesocket (sok);
+		free (username);
+		return 0;
+	}
+
+	len = sizeof (addr);
+	read_sok = accept (sok, (struct sockaddr *) &addr, &len);
+	closesocket (sok);
+
+	if (read_sok == INVALID_SOCKET)
+	{
+		free (username);
+		return 0;
+	}
+
+	identd_ipv6_is_running = FALSE;
+
+	if (WSAAddressToString ((struct sockaddr *) &addr, sizeof (addr), NULL, &ipv6buf, &ipv6buflen) == SOCKET_ERROR)
+	{
+		snprintf (ipv6buf, sizeof (ipv6buf) - 1, "[SOCKET ERROR: 0x%X]", WSAGetLastError ());
+	}
+
+	snprintf (outbuf, sizeof (outbuf), "%%\tServicing ident request from %s\n", ipv6buf);
+	PrintText (current_sess, outbuf);
+
+	recv (read_sok, buf, sizeof (buf) - 1, 0);
+	buf[sizeof (buf) - 1] = 0;	  /* ensure null termination */
+
+	p = strchr (buf, ',');
+
+	if (p)
+	{
+		snprintf (outbuf, sizeof (outbuf) - 1, "%d, %d : USERID : UNIX : %s\r\n", atoi (buf), atoi (p + 1), username);
+		outbuf[sizeof (outbuf) - 1] = 0;	/* ensure null termination */
+		send (read_sok, outbuf, strlen (outbuf), 0);
+	}
+
+	sleep (1);
+	closesocket (read_sok);
+	free (username);
+
+	return 0;
+}
+#endif
+
+void
 identd_start (char *username)
 {
 	DWORD tid;
 
+#ifdef USE_IPV6
+	DWORD tidv6;
+	if (identd_ipv6_is_running == FALSE)
+	{
+		identd_ipv6_is_running = TRUE;
+		CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) identd_ipv6,
+						 strdup (username), 0, &tidv6));
+	}
+#endif
+
 	if (identd_is_running == FALSE)
 	{
 		identd_is_running = TRUE;
diff --git a/src/common/identd.h b/src/common/identd.h
new file mode 100644
index 00000000..636f9641
--- /dev/null
+++ b/src/common/identd.h
@@ -0,0 +1 @@
+void identd_start (char *username);
diff --git a/src/common/ignore.c b/src/common/ignore.c
index c3544f30..0ed23daa 100644
--- a/src/common/ignore.c
+++ b/src/common/ignore.c
@@ -19,11 +19,14 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat.h"
 #include "ignore.h"
 #include "cfgfiles.h"
diff --git a/src/common/inbound.c b/src/common/inbound.c
index 719bbe60..89899655 100644
--- a/src/common/inbound.c
+++ b/src/common/inbound.c
@@ -21,9 +21,12 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <unistd.h>
 #include <time.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #define WANTARPA
 #define WANTDNS
 #include "inet.h"
@@ -883,7 +886,7 @@ inbound_notice (server *serv, char *to, char *nick, char *msg, char *ip, int id)
 			if (msg[0] == '[' && (!serv->have_idmsg || id))
 			{
 				/* guess where chanserv meant to post this -sigh- */
-				if (!strcasecmp (nick, "ChanServ") && !find_dialog (serv, nick))
+				if (!g_ascii_strcasecmp (nick, "ChanServ") && !find_dialog (serv, nick))
 				{
 					char *dest = strdup (msg + 1);
 					char *end = strchr (dest, ']');
diff --git a/src/common/inet.h b/src/common/inet.h
index b420c9c6..8995569c 100644
--- a/src/common/inet.h
+++ b/src/common/inet.h
@@ -21,12 +21,12 @@
 
 #else
 
+#include "../../config.h"
 #ifdef USE_IPV6
 #include <winsock2.h>
 #include <ws2tcpip.h>
-#include <tpipv6.h>
 #else
-#include <winsock.h>
+#include <winsock2.h>
 #endif
 
 #define set_blocking(sok)	{ \
diff --git a/src/common/makefile.mak b/src/common/makefile.mak
new file mode 100644
index 00000000..d6df2608
--- /dev/null
+++ b/src/common/makefile.mak
@@ -0,0 +1,45 @@
+include "..\makeinc.mak"
+
+COMMON_OBJECTS = \
+cfgfiles.obj \
+chanopt.obj \
+ctcp.obj \
+dcc.obj \
+dirent-win32.obj \
+history.obj \
+identd.obj \
+ignore.obj \
+inbound.obj \
+modes.obj \
+network.obj \
+notify.obj \
+outbound.obj \
+plugin.obj \
+plugin-timer.obj \
+proto-irc.obj \
+server.obj \
+servlist.obj \
+ssl.obj \
+text.obj \
+thread.obj \
+tree.obj \
+url.obj \
+userlist.obj \
+util.obj \
+xchat.obj
+
+all: $(COMMON_OBJECTS) xchatcommon.lib dirent-win32.lib
+
+xchatcommon.lib: $(COMMON_OBJECTS)
+	lib /nologo /out:xchatcommon.lib $(COMMON_OBJECTS)
+
+dirent-win32.lib: dirent-win32.obj
+	lib /nologo /out:dirent-win32.lib dirent-win32.obj
+
+.c.obj::
+	$(CC) $(CFLAGS) $(GLIB) $<
+
+clean:
+	@del *.obj
+	@del xchatcommon.lib
+	@del dirent-win32.lib
diff --git a/src/common/modes.c b/src/common/modes.c
index 1acf7f54..6eb63f3b 100644
--- a/src/common/modes.c
+++ b/src/common/modes.c
@@ -789,20 +789,20 @@ inbound_005 (server * serv, char *word[])
 			}
 
 			/* use /NICKSERV */
-			if (strcasecmp (word[w] + 8, "RusNet") == 0)
+			if (g_ascii_strcasecmp (word[w] + 8, "RusNet") == 0)
 				serv->nickservtype = 1;
-			else if (strcasecmp (word[w] + 8, "UniBG") == 0)
+			else if (g_ascii_strcasecmp (word[w] + 8, "UniBG") == 0)
 				serv->nickservtype = 3;
-			else if (strcasecmp (word[w] + 8, "QuakeNet") == 0)
+			else if (g_ascii_strcasecmp (word[w] + 8, "QuakeNet") == 0)
 				serv->nickservtype = 4;
 
 		} else if (strncmp (word[w], "CASEMAPPING=", 12) == 0)
 		{
 			if (strcmp (word[w] + 12, "ascii") == 0)	/* bahamut */
-				serv->p_cmp = (void *)strcasecmp;
+				serv->p_cmp = (void *)g_ascii_strcasecmp;
 		} else if (strncmp (word[w], "CHARSET=", 8) == 0)
 		{
-			if (strcasecmp (word[w] + 8, "UTF-8") == 0)
+			if (g_ascii_strcasecmp (word[w] + 8, "UTF-8") == 0)
 			{
 				server_set_encoding (serv, "UTF-8");
 			}
diff --git a/src/common/msproxy.c b/src/common/msproxy.c
index 9c85394d..5103233a 100644
--- a/src/common/msproxy.c
+++ b/src/common/msproxy.c
@@ -26,9 +26,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <fcntl.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #define WANTSOCKET
 #define WANTARPA
 #include "inet.h"
diff --git a/src/common/network.c b/src/common/network.c
index 0c409506..eba24b05 100644
--- a/src/common/network.c
+++ b/src/common/network.c
@@ -21,9 +21,12 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <glib.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "../../config.h"				  /* grab USE_IPV6 and LOOKUPD defines */
 
 #define WANTSOCKET
diff --git a/src/common/notify.c b/src/common/notify.c
index 04795849..9c6e54de 100644
--- a/src/common/notify.c
+++ b/src/common/notify.c
@@ -22,9 +22,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <time.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat.h"
 #include "notify.h"
 #include "cfgfiles.h"
diff --git a/src/common/outbound.c b/src/common/outbound.c
index 2add05fd..872ef50b 100644
--- a/src/common/outbound.c
+++ b/src/common/outbound.c
@@ -30,9 +30,9 @@
 
 #ifndef WIN32
 #include <sys/wait.h>
+#include <unistd.h>
 #endif
 
-#include <unistd.h>
 #include <time.h>
 #include <signal.h>
 #include <sys/stat.h>
@@ -617,13 +617,13 @@ cmd_clear (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	GSList *list = sess_list;
 	char *reason = word_eol[2];
 
-	if (strcasecmp (reason, "HISTORY") == 0)
+	if (g_ascii_strcasecmp (reason, "HISTORY") == 0)
 	{
 		history_free (&sess->history);
 		return TRUE;
 	}
 
-	if (strncasecmp (reason, "all", 3) == 0)
+	if (g_ascii_strncasecmp (reason, "all", 3) == 0)
 	{
 		while (list)
 		{
@@ -750,26 +750,26 @@ cmd_dcc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	char *type = word[2];
 	if (*type)
 	{
-		if (!strcasecmp (type, "HELP"))
+		if (!g_ascii_strcasecmp (type, "HELP"))
 			return FALSE;
-		if (!strcasecmp (type, "CLOSE"))
+		if (!g_ascii_strcasecmp (type, "CLOSE"))
 		{
 			if (*word[3] && *word[4])
 			{
 				goodtype = 0;
-				if (!strcasecmp (word[3], "SEND"))
+				if (!g_ascii_strcasecmp (word[3], "SEND"))
 				{
 					dcc = find_dcc (word[4], word[5], TYPE_SEND);
 					dcc_abort (sess, dcc);
 					goodtype = TRUE;
 				}
-				if (!strcasecmp (word[3], "GET"))
+				if (!g_ascii_strcasecmp (word[3], "GET"))
 				{
 					dcc = find_dcc (word[4], word[5], TYPE_RECV);
 					dcc_abort (sess, dcc);
 					goodtype = TRUE;
 				}
-				if (!strcasecmp (word[3], "CHAT"))
+				if (!g_ascii_strcasecmp (word[3], "CHAT"))
 				{
 					dcc = find_dcc (word[4], "", TYPE_CHATRECV);
 					if (!dcc)
@@ -789,20 +789,20 @@ cmd_dcc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 			}
 			return FALSE;
 		}
-		if ((!strcasecmp (type, "CHAT")) || (!strcasecmp (type, "PCHAT")))
+		if ((!g_ascii_strcasecmp (type, "CHAT")) || (!g_ascii_strcasecmp (type, "PCHAT")))
 		{
 			char *nick = word[3];
-			int passive = (!strcasecmp(type, "PCHAT")) ? 1 : 0;
+			int passive = (!g_ascii_strcasecmp(type, "PCHAT")) ? 1 : 0;
 			if (*nick)
 				dcc_chat (sess, nick, passive);
 			return TRUE;
 		}
-		if (!strcasecmp (type, "LIST"))
+		if (!g_ascii_strcasecmp (type, "LIST"))
 		{
 			dcc_show_list (sess);
 			return TRUE;
 		}
-		if (!strcasecmp (type, "GET"))
+		if (!g_ascii_strcasecmp (type, "GET"))
 		{
 			char *nick = word[3];
 			char *file = word[4];
@@ -820,18 +820,18 @@ cmd_dcc (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 			}
 			return TRUE;
 		}
-		if ((!strcasecmp (type, "SEND")) || (!strcasecmp (type, "PSEND")))
+		if ((!g_ascii_strcasecmp (type, "SEND")) || (!g_ascii_strcasecmp (type, "PSEND")))
 		{
 			int i = 3, maxcps;
 			char *nick, *file;
-			int passive = (!strcasecmp(type, "PSEND")) ? 1 : 0;
+			int passive = (!g_ascii_strcasecmp(type, "PSEND")) ? 1 : 0;
 
 			nick = word[i];
 			if (!*nick)
 				return FALSE;
 
 			maxcps = prefs.dcc_max_send_cps;
-			if (!strncasecmp(nick, "-maxcps=", 8))
+			if (!g_ascii_strncasecmp(nick, "-maxcps=", 8))
 			{
 				maxcps = atoi(nick + 8);
 				i++;
@@ -1312,7 +1312,7 @@ cmd_menu (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 				*p = '/';
 	}
 
-	if (!strcasecmp (word[idx], "ADD"))
+	if (!g_ascii_strcasecmp (word[idx], "ADD"))
 	{
 		if (toggle)
 		{
@@ -1327,7 +1327,7 @@ cmd_menu (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 		return TRUE;
 	}
 
-	if (!strcasecmp (word[idx], "DEL"))
+	if (!g_ascii_strcasecmp (word[idx], "DEL"))
 	{
 		menu_del (tbuf, label);
 		return TRUE;
@@ -2045,7 +2045,7 @@ cmd_gui (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	case 0xc0851aaa: fe_message (word[3], FE_MSG_INFO|FE_MSG_MARKUP); break; /* MSGBOX */
 	case 0x0035dafd: fe_ctrl_gui (sess, 1, 0); break; /* SHOW */
 	case 0x0033155f: /* MENU */
-		if (!strcasecmp (word[3], "TOGGLE"))
+		if (!g_ascii_strcasecmp (word[3], "TOGGLE"))
 			fe_ctrl_gui (sess, 6, 0);
 		else
 			return FALSE;
@@ -2247,25 +2247,25 @@ cmd_ignore (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 			}
 			return TRUE;
 		}
-		if (!strcasecmp (word[i], "UNIGNORE"))
+		if (!g_ascii_strcasecmp (word[i], "UNIGNORE"))
 			type |= IG_UNIG;
-		else if (!strcasecmp (word[i], "ALL"))
+		else if (!g_ascii_strcasecmp (word[i], "ALL"))
 			type |= IG_PRIV | IG_NOTI | IG_CHAN | IG_CTCP | IG_INVI | IG_DCC;
-		else if (!strcasecmp (word[i], "PRIV"))
+		else if (!g_ascii_strcasecmp (word[i], "PRIV"))
 			type |= IG_PRIV;
-		else if (!strcasecmp (word[i], "NOTI"))
+		else if (!g_ascii_strcasecmp (word[i], "NOTI"))
 			type |= IG_NOTI;
-		else if (!strcasecmp (word[i], "CHAN"))
+		else if (!g_ascii_strcasecmp (word[i], "CHAN"))
 			type |= IG_CHAN;
-		else if (!strcasecmp (word[i], "CTCP"))
+		else if (!g_ascii_strcasecmp (word[i], "CTCP"))
 			type |= IG_CTCP;
-		else if (!strcasecmp (word[i], "INVI"))
+		else if (!g_ascii_strcasecmp (word[i], "INVI"))
 			type |= IG_INVI;
-		else if (!strcasecmp (word[i], "QUIET"))
+		else if (!g_ascii_strcasecmp (word[i], "QUIET"))
 			quiet = 1;
-		else if (!strcasecmp (word[i], "NOSAVE"))
+		else if (!g_ascii_strcasecmp (word[i], "NOSAVE"))
 			type |= IG_NOSAVE;
-		else if (!strcasecmp (word[i], "DCC"))
+		else if (!g_ascii_strcasecmp (word[i], "DCC"))
 			type |= IG_DCC;
 		else
 		{
@@ -2456,12 +2456,12 @@ cmd_load (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 #ifdef USE_PLUGIN
 	len = strlen (word[2]);
 #ifdef WIN32
-	if (len > 4 && strcasecmp (".dll", word[2] + len - 4) == 0)
+	if (len > 4 && g_ascii_strcasecmp (".dll", word[2] + len - 4) == 0)
 #else
 #if defined(__hpux)
-	if (len > 3 && strcasecmp (".sl", word[2] + len - 3) == 0)
+	if (len > 3 && g_ascii_strcasecmp (".sl", word[2] + len - 3) == 0)
 #else
-	if (len > 3 && strcasecmp (".so", word[2] + len - 3) == 0)
+	if (len > 3 && g_ascii_strcasecmp (".so", word[2] + len - 3) == 0)
 #endif
 #endif
 	{
@@ -2613,8 +2613,8 @@ cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 			else
 			{
 				/* mask out passwords */
-				if (strcasecmp (nick, "nickserv") == 0 &&
-					 strncasecmp (msg, "identify ", 9) == 0)
+				if (g_ascii_strcasecmp (nick, "nickserv") == 0 &&
+					 g_ascii_strncasecmp (msg, "identify ", 9) == 0)
 					msg = "identify ****";
 				EMIT_SIGNAL (XP_TE_MSGSEND, sess, nick, msg, NULL, NULL, 0);
 			}
@@ -2825,7 +2825,7 @@ cmd_reconnect (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 
 	prefs.recon_delay = 0;
 
-	if (!strcasecmp (word[2], "ALL"))
+	if (!g_ascii_strcasecmp (word[2], "ALL"))
 	{
 		list = serv_list;
 		while (list)
@@ -2881,6 +2881,23 @@ cmd_recv (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	return FALSE;
 }
 
+#if 0 /* manual command for flushing prefs to disk, but we use an autosave-upon-set approach instead */
+static int
+cmd_saveconf (struct session *sess, char *tbuf, char *word[], char *word_eol[])
+{
+	if (save_config ())
+	{
+		PrintText (sess, "Settings have been saved successfully.\n");
+	}
+	else
+	{
+		PrintText (sess, "Error saving settings.\n");
+	}
+
+	return TRUE;
+}
+#endif
+
 static int
 cmd_say (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 {
@@ -2980,7 +2997,7 @@ parse_irc_url (char *url, char *server_name[], char *port[], char *channel[], in
 {
 	char *co;
 #ifdef USE_OPENSSL
-	if (strncasecmp ("ircs://", url, 7) == 0)
+	if (g_ascii_strncasecmp ("ircs://", url, 7) == 0)
 	{
 		*use_ssl = TRUE;
 		*server_name = url + 7;
@@ -2988,7 +3005,7 @@ parse_irc_url (char *url, char *server_name[], char *port[], char *channel[], in
 	}
 #endif
 
-	if (strncasecmp ("irc://", url, 6) == 0)
+	if (g_ascii_strncasecmp ("irc://", url, 6) == 0)
 	{
 		*server_name = url + 6;
 #ifdef USE_OPENSSL
@@ -3059,7 +3076,7 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 	sess->server->network = NULL;
 
 	/* dont clear it for /servchan */
-	if (strncasecmp (word_eol[1], "SERVCHAN ", 9))
+	if (g_ascii_strncasecmp (word_eol[1], "SERVCHAN ", 9))
 		sess->willjoinchannel[0] = 0;
 
 	if (channel)
@@ -3189,7 +3206,7 @@ cmd_unignore (struct session *sess, char *tbuf, char *word[],
 	{
 		if (ignore_del (mask, NULL))
 		{
-			if (strcasecmp (arg, "QUIET"))
+			if (g_ascii_strcasecmp (arg, "QUIET"))
 				EMIT_SIGNAL (XP_TE_IGNOREREMOVE, sess, mask, NULL, NULL, NULL, 0);
 		}
 		return TRUE;
@@ -3205,12 +3222,12 @@ cmd_unload (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 
 	len = strlen (word[2]);
 #ifdef WIN32
-	if (len > 4 && strcasecmp (word[2] + len - 4, ".dll") == 0)
+	if (len > 4 && g_ascii_strcasecmp (word[2] + len - 4, ".dll") == 0)
 #else
 #if defined(__hpux)
-	if (len > 3 && strcasecmp (word[2] + len - 3, ".sl") == 0)
+	if (len > 3 && g_ascii_strcasecmp (word[2] + len - 3, ".sl") == 0)
 #else
-	if (len > 3 && strcasecmp (word[2] + len - 3, ".so") == 0)
+	if (len > 3 && g_ascii_strcasecmp (word[2] + len - 3, ".so") == 0)
 #endif
 #endif
 		by_file = TRUE;
@@ -3240,7 +3257,7 @@ find_server_from_hostname (char *hostname)
 	while (list)
 	{
 		serv = list->data;
-		if (!strcasecmp (hostname, serv->hostname) && serv->connected)
+		if (!g_ascii_strcasecmp (hostname, serv->hostname) && serv->connected)
 			return serv;
 		list = list->next;
 	}
@@ -3293,7 +3310,7 @@ cmd_url (struct session *sess, char *tbuf, char *word[], char *word_eol[])
 			/* maybe we're already connected to this net */
 
 			/* check for "FreeNode" */
-			net = servlist_net_find (server_name, NULL, strcasecmp);
+			net = servlist_net_find (server_name, NULL, g_ascii_strcasecmp);
 			/* check for "irc.eu.freenode.net" */
 			if (!net)
 				net = servlist_net_find_from_server (server_name);
@@ -3633,6 +3650,9 @@ const struct commands xc_cmds[] = {
 #endif
 	{"RECV", cmd_recv, 1, 0, 1, N_("RECV <text>, send raw data to xchat, as if it was received from the irc server")},
 
+#if 0
+	{"SAVECONF", cmd_saveconf, 0, 0, 1, N_("SAVECONF, saves the current settings to disk")},
+#endif
 	{"SAY", cmd_say, 0, 0, 1,
 	 N_("SAY <text>, sends the text to the object in the current window")},
 	{"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
@@ -3685,7 +3705,7 @@ const struct commands xc_cmds[] = {
 static int
 command_compare (const void *a, const void *b)
 {
-	return strcasecmp (a, ((struct commands *)b)->name);
+	return g_ascii_strcasecmp (a, ((struct commands *)b)->name);
 }
 
 static struct commands *
@@ -4257,7 +4277,7 @@ handle_command (session *sess, char *cmd, int check_spch)
 	while (list)
 	{
 		pop = (struct popup *) list->data;
-		if (!strcasecmp (pop->name, word[1]))
+		if (!g_ascii_strcasecmp (pop->name, word[1]))
 		{
 			user_command (sess, tbuf, pop->cmd, word, word_eol);
 			user_cmd = TRUE;
diff --git a/src/common/plugin-timer.c b/src/common/plugin-timer.c
index f09074a8..431ce8ab 100644
--- a/src/common/plugin-timer.c
+++ b/src/common/plugin-timer.c
@@ -4,7 +4,7 @@
 #include "xchat-plugin.h"
 
 #ifdef WIN32
-#define strcasecmp stricmp
+#define g_ascii_strcasecmp stricmp
 #endif
 
 static xchat_plugin *ph;	/* plugin handle */
@@ -151,25 +151,25 @@ timer_cb (char *word[], char *word_eol[], void *userdata)
 		return XCHAT_EAT_XCHAT;
 	}
 
-	if (strcasecmp (word[2], "-quiet") == 0)
+	if (g_ascii_strcasecmp (word[2], "-quiet") == 0)
 	{
 		quiet = TRUE;
 		offset++;
 	}
 
-	if (strcasecmp (word[2 + offset], "-delete") == 0)
+	if (g_ascii_strcasecmp (word[2 + offset], "-delete") == 0)
 	{
 		timer_del_ref (atoi (word[3 + offset]), quiet);
 		return XCHAT_EAT_XCHAT;
 	}
 
-	if (strcasecmp (word[2 + offset], "-refnum") == 0)
+	if (g_ascii_strcasecmp (word[2 + offset], "-refnum") == 0)
 	{
 		ref = atoi (word[3 + offset]);
 		offset += 2;
 	}
 
-	if (strcasecmp (word[2 + offset], "-repeat") == 0)
+	if (g_ascii_strcasecmp (word[2 + offset], "-repeat") == 0)
 	{
 		repeat = atoi (word[3 + offset]);
 		offset += 2;
diff --git a/src/common/plugin.c b/src/common/plugin.c
index ada4d3be..0a265d16 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -20,6 +20,14 @@
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
 
 #include "xchat.h"
 #include "fe.h"
@@ -262,6 +270,12 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
 		pl->xchat_send_modes = xchat_send_modes;
 		pl->xchat_strip = xchat_strip;
 		pl->xchat_free = xchat_free;
+		pl->xchat_pluginpref_set_str = xchat_pluginpref_set_str;
+		pl->xchat_pluginpref_get_str = xchat_pluginpref_get_str;
+		pl->xchat_pluginpref_set_int = xchat_pluginpref_set_int;
+		pl->xchat_pluginpref_get_int = xchat_pluginpref_get_int;
+		pl->xchat_pluginpref_delete = xchat_pluginpref_delete;
+		pl->xchat_pluginpref_list = xchat_pluginpref_list;
 
 		/* incase new plugins are loaded on older xchat */
 		pl->xchat_dummy4 = xchat_dummy;
@@ -295,9 +309,9 @@ plugin_kill (char *name, int by_filename)
 	{
 		pl = list->data;
 		/* static-plugins (plugin-timer.c) have a NULL filename */
-		if ((by_filename && pl->filename && strcasecmp (name, pl->filename) == 0) ||
-			 (by_filename && pl->filename && strcasecmp (name, file_part (pl->filename)) == 0) ||
-			(!by_filename && strcasecmp (name, pl->name) == 0))
+		if ((by_filename && pl->filename && g_ascii_strcasecmp (name, pl->filename) == 0) ||
+			 (by_filename && pl->filename && g_ascii_strcasecmp (name, file_part (pl->filename)) == 0) ||
+			(!by_filename && g_ascii_strcasecmp (name, pl->name) == 0))
 		{
 			/* statically linked plugins have a NULL filename */
 			if (pl->filename != NULL && !pl->fake)
@@ -458,12 +472,12 @@ plugin_hook_find (GSList *list, int type, char *name)
 		hook = list->data;
 		if (hook->type == type)
 		{
-			if (strcasecmp (hook->name, name) == 0)
+			if (g_ascii_strcasecmp (hook->name, name) == 0)
 				return list;
 
 			if (type == HOOK_SERVER)
 			{
-				if (strcasecmp (hook->name, "RAW LINE") == 0)
+				if (g_ascii_strcasecmp (hook->name, "RAW LINE") == 0)
 					return list;
 			}
 		}
@@ -933,8 +947,8 @@ xchat_find_context (xchat_plugin *ph, const char *servname, const char *channel)
 
 		if (servname == NULL ||
 			 rfc_casecmp (servname, serv->servername) == 0 ||
-			 strcasecmp (servname, serv->hostname) == 0 ||
-			 strcasecmp (servname, netname) == 0)
+			 g_ascii_strcasecmp (servname, serv->hostname) == 0 ||
+			 g_ascii_strcasecmp (servname, netname) == 0)
 		{
 			if (channel == NULL)
 				return serv->front_session;
@@ -996,13 +1010,20 @@ xchat_get_info (xchat_plugin *ph, const char *id)
 		return XCHATLIBDIR;
 
 	case 0x14f51cd8: /* version */
+#ifdef WIN32
+		return XCHAT_RELEASE;
+#else
 		return PACKAGE_VERSION;
+#endif
 
 	case 0xdd9b1abd:	/* xchatdir */
 		return get_xdir_utf8 ();
 
 	case 0xe33f6c4a:	/* xchatdirfs */
 		return get_xdir_fs ();
+
+	case 0x3d1e70d7:	/* wdk_version */
+		return PACKAGE_VERSION;
 	}
 
 	sess = ph->context;
@@ -1100,7 +1121,7 @@ xchat_get_prefs (xchat_plugin *ph, const char *name, const char **string, int *i
 	
 	do
 	{
-		if (!strcasecmp (name, vars[i].name))
+		if (!g_ascii_strcasecmp (name, vars[i].name))
 		{
 			switch (vars[i].type)
 			{
@@ -1567,3 +1588,239 @@ xchat_free (xchat_plugin *ph, void *ptr)
 {
 	g_free (ptr);
 }
+
+static int
+xchat_pluginpref_set_str_real (xchat_plugin *pl, const char *var, const char *value, int mode) /* mode: 0 = delete, 1 = save */
+{
+	FILE *fpIn;
+	int fhOut;
+	int prevSetting;
+	char confname[64];
+	char confname_tmp[69];
+	char buffer[512];		/* the same as in cfg_put_str */
+	char buffer_tmp[512];
+	char *canon;
+
+	canon = g_strdup (pl->name);
+	canonalize_key (canon);
+	sprintf (confname, "plugin_%s.conf", canon);
+	g_free (canon);
+	sprintf (confname_tmp, "%s.new", confname);
+
+	fhOut = xchat_open_file (confname_tmp, O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
+	fpIn = xchat_fopen_file (confname, "r", 0);
+
+	if (fhOut == -1)		/* unable to save, abort */
+	{
+		return 0;
+	}
+	else if (fpIn == NULL)	/* no previous config file, no parsing */
+	{
+		if (mode)
+		{
+			sprintf (buffer, "%s = %s\n", var, value);
+			write (fhOut, buffer, strlen (buffer));
+			close (fhOut);
+
+			sprintf (buffer, "%s/%s", get_xdir_fs (), confname);
+			sprintf (buffer_tmp, "%s/%s", get_xdir_fs (), confname_tmp);
+
+#ifdef WIN32
+			unlink (buffer);
+#endif
+
+			if (rename (buffer_tmp, buffer) == 0)
+			{
+				return 1;
+			}
+			else
+			{
+				return 0;
+			}
+		}
+		else
+		{
+			/* mode = 0, we want to delete but the config file and thus the given setting does not exist, we're ready */
+			close (fhOut);
+			return 1;
+		}
+	}
+	else	/* existing config file, preserve settings and find & replace current var value if any */
+	{
+		prevSetting = 0;
+
+		while (fscanf (fpIn, " %[^\n]", &buffer) != EOF)	/* read whole lines including whitespaces */
+		{
+			sprintf (buffer_tmp, "%s ", var);				/* add one space, this way it works against var - var2 checks too */
+
+			if (strncmp (buffer_tmp, buffer, strlen (var) + 1) == 0)	/* given setting already exists */
+			{
+				if (mode)									/* overwrite the existing matching setting if we are in save mode */
+				{
+					sprintf (buffer, "%s = %s\n", var, value);
+				}
+				else										/* erase the setting in delete mode */
+				{
+					strcpy (buffer, "");
+				}
+
+				prevSetting = 1;
+			}
+			else
+			{
+				strcat (buffer, "\n");						/* preserve the existing different settings */
+			}
+
+			write (fhOut, buffer, strlen (buffer));
+		}
+
+		fclose (fpIn);
+
+		if (!prevSetting && mode)	/* var doesn't exist currently, append if we're in save mode */
+		{
+			sprintf (buffer, "%s = %s\n", var, value);
+			write (fhOut, buffer, strlen (buffer));
+		}
+
+		close (fhOut);
+
+		sprintf (buffer, "%s/%s", get_xdir_fs (), confname);
+		sprintf (buffer_tmp, "%s/%s", get_xdir_fs (), confname_tmp);
+
+#ifdef WIN32
+		unlink (buffer);
+#endif
+
+		if (rename (buffer_tmp, buffer) == 0)
+		{
+			return 1;
+		}
+		else
+		{
+			return 0;
+		}
+	}
+}
+
+int
+xchat_pluginpref_set_str (xchat_plugin *pl, const char *var, const char *value)
+{
+	return xchat_pluginpref_set_str_real (pl, var, value, 1);
+}
+
+int
+xchat_pluginpref_get_str (xchat_plugin *pl, const char *var, char *dest)
+{
+	int fh;
+	int l;
+	char confname[64];
+	char *canon;
+	char *cfg;
+	struct stat st;
+
+	canon = g_strdup (pl->name);
+	canonalize_key (canon);
+	sprintf (confname, "plugin_%s.conf", canon);
+	g_free (canon);
+
+	/* partly borrowed from palette.c */
+	fh = xchat_open_file (confname, O_RDONLY, 0, 0);
+
+	if (fh == -1)
+	{
+		return 0;
+	}
+
+	fstat (fh, &st);
+	cfg = malloc (st.st_size + 1);
+
+	if (!cfg)
+	{
+		close (fh);
+		return 0;
+	}
+
+	cfg[0] = '\0';
+	l = read (fh, cfg, st.st_size);
+
+	if (l >= 0)
+	{
+		cfg[l] = '\0';
+	}
+
+	if (!cfg_get_str (cfg, var, dest, 512)) /* dest_len is the same as buffer size in set */
+	{
+		free (cfg);
+		close (fh);
+		return 0;
+	}
+
+	free (cfg);
+	close (fh);
+	return 1;
+}
+
+int
+xchat_pluginpref_set_int (xchat_plugin *pl, const char *var, int value)
+{
+	char buffer[12];
+
+	sprintf (buffer, "%d", value);
+	return xchat_pluginpref_set_str_real (pl, var, buffer, 1);
+}
+
+int
+xchat_pluginpref_get_int (xchat_plugin *pl, const char *var)
+{
+	char buffer[12];
+
+	if (xchat_pluginpref_get_str (pl, var, buffer))
+	{
+		return atoi (buffer);
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+int
+xchat_pluginpref_delete (xchat_plugin *pl, const char *var)
+{
+	return xchat_pluginpref_set_str_real (pl, var, 0, 0);
+}
+
+int
+xchat_pluginpref_list (xchat_plugin *pl, char* dest)
+{
+	FILE *fpIn;
+	char confname[64];
+	char buffer[512];										/* the same as in cfg_put_str */
+	char *token;
+
+	token = g_strdup (pl->name);
+	canonalize_key (token);
+	sprintf (confname, "plugin_%s.conf", token);
+	g_free (token);
+
+	fpIn = xchat_fopen_file (confname, "r", 0);
+
+	if (fpIn == NULL)										/* no existing config file, no parsing */
+	{
+		return 0;
+	}
+	else													/* existing config file, get list of settings */
+	{
+		strcpy (dest, "");									/* clean up garbage */
+		while (fscanf (fpIn, " %[^\n]", &buffer) != EOF)	/* read whole lines including whitespaces */
+		{
+			token = strtok (buffer, "=");
+			strncat (dest, token, strlen (token) - 1);
+			strcat (dest, ",");
+		}
+
+		fclose (fpIn);
+	}
+
+	return 1;
+}
diff --git a/src/common/plugin.h b/src/common/plugin.h
index b0c89d1b..8c347d51 100644
--- a/src/common/plugin.h
+++ b/src/common/plugin.h
@@ -98,6 +98,21 @@ struct _xchat_plugin
 	     int flags);
 	void (*xchat_free) (xchat_plugin *ph,
 	    void *ptr);
+	int (*xchat_pluginpref_set_str) (xchat_plugin *ph,
+		const char *var,
+		const char *value);
+	int (*xchat_pluginpref_get_str) (xchat_plugin *ph,
+		const char *var,
+		char *dest);
+	int (*xchat_pluginpref_set_int) (xchat_plugin *ph,
+		const char *var,
+		int value);
+	int (*xchat_pluginpref_get_int) (xchat_plugin *ph,
+		const char *var);
+	int (*xchat_pluginpref_delete) (xchat_plugin *ph,
+		const char *var);
+	int (*xchat_pluginpref_list) (xchat_plugin *ph,
+		char *dest);
 	void *(*xchat_dummy4) (xchat_plugin *ph);
 	void *(*xchat_dummy3) (xchat_plugin *ph);
 	void *(*xchat_dummy2) (xchat_plugin *ph);
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index 338a3b18..d8a6be7c 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -18,13 +18,16 @@
 
 /* IRC RFC1459(+commonly used extensions) protocol implementation */
 
-#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdarg.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat.h"
 #include "ctcp.h"
 #include "fe.h"
@@ -472,12 +475,12 @@ process_numeric (session * sess, int n,
 		}
 
 		/* use /NICKSERV */
-		if (strcasecmp (word[7], "DALnet") == 0 ||
-			 strcasecmp (word[7], "BRASnet") == 0)
+		if (g_ascii_strcasecmp (word[7], "DALnet") == 0 ||
+			 g_ascii_strcasecmp (word[7], "BRASnet") == 0)
 			serv->nickservtype = 1;
 
 		/* use /NS */
-		else if (strcasecmp (word[7], "FreeNode") == 0)
+		else if (g_ascii_strcasecmp (word[7], "FreeNode") == 0)
 			serv->nickservtype = 2;
 
 		goto def;
@@ -1072,9 +1075,9 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
 					{
 						text[len - 1] = 0;
 						text++;
-						if (strncasecmp (text, "ACTION", 6) != 0)
+						if (g_ascii_strncasecmp (text, "ACTION", 6) != 0)
 							flood_check (nick, ip, serv, sess, 0);
-						if (strncasecmp (text, "DCC ", 4) == 0)
+						if (g_ascii_strncasecmp (text, "DCC ", 4) == 0)
 							/* redo this with handle_quotes TRUE */
 							process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE);
 						ctcp_handle (sess, to, nick, ip, text, word, word_eol, id);
diff --git a/src/common/server.c b/src/common/server.c
index db0af9ca..c8cc59e0 100644
--- a/src/common/server.c
+++ b/src/common/server.c
@@ -26,7 +26,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
 
@@ -37,6 +36,7 @@
 #ifndef WIN32
 #include <signal.h>
 #include <sys/wait.h>
+#include <unistd.h>
 #else
 #include <winbase.h>
 #endif
@@ -67,7 +67,7 @@
 #endif
 
 #ifdef WIN32
-#include "identd.c"
+#include "identd.h"
 #endif
 
 #ifdef USE_LIBPROXY
@@ -238,17 +238,17 @@ tcp_send_len (server *serv, char *buf, int len)
 	dbuf[len + 1] = 0;
 
 	/* privmsg and notice get a lower priority */
-	if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
-		 strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
+	if (g_ascii_strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
+		 g_ascii_strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
 	{
 		dbuf[0] = 1;
 	}
 	else
 	{
 		/* WHO/MODE get the lowest priority */
-		if (strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
+		if (g_ascii_strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
 		/* but only MODE queries, not changes */
-			(strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
+			(g_ascii_strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
 			 strchr (dbuf, '-') == NULL &&
 			 strchr (dbuf, '+') == NULL))
 			dbuf[0] = 0;
@@ -310,12 +310,17 @@ server_inline (server *serv, char *line, int len)
 {
 	char *utf_line_allocated = NULL;
 
+#ifdef WIN32
+	char *cleaned_line;
+	int cleaned_len;
+#endif
+
 	/* Checks whether we're set to use UTF-8 charset */
 	if (serv->using_irc ||				/* 1. using CP1252/UTF-8 Hybrid */
 		(serv->encoding == NULL && prefs.utf8_locale) || /* OR 2. using system default->UTF-8 */
 	    (serv->encoding != NULL &&				/* OR 3. explicitly set to UTF-8 */
-		 (strcasecmp (serv->encoding, "UTF8") == 0 ||
-		  strcasecmp (serv->encoding, "UTF-8") == 0)))
+		 (g_ascii_strcasecmp (serv->encoding, "UTF8") == 0 ||
+		  g_ascii_strcasecmp (serv->encoding, "UTF-8") == 0)))
 	{
 		/* The user has the UTF-8 charset set, either via /charset
 		command or from his UTF-8 locale. Thus, we first try the
@@ -396,11 +401,23 @@ server_inline (server *serv, char *line, int len)
 		}
 	}
 
+#ifdef WIN32
+	cleaned_line = text_replace_non_bmp (line, len, &cleaned_len);
+	if (cleaned_line != NULL ) {
+		line = cleaned_line;
+		len = cleaned_len;
+	}
+#endif
+
 	fe_add_rawlog (serv, line, len, FALSE);
 
 	/* let proto-irc.c handle it */
 	serv->p_inline (serv, line, len);
 
+#ifdef WIN32
+	g_free (cleaned_line);
+#endif
+
 	if (utf_line_allocated != NULL) /* only if a special copy was allocated */
 		g_free (utf_line_allocated);
 }
@@ -844,33 +861,6 @@ server_flush_queue (server *serv)
 	fe_set_throttle (serv);
 }
 
-#ifdef WIN32
-
-static int
-waitline2 (GIOChannel *source, char *buf, int bufsize)
-{
-	int i = 0;
-	int len;
-
-	while (1)
-	{
-		if (g_io_channel_read (source, &buf[i], 1, &len) != G_IO_ERROR_NONE)
-			return -1;
-		if (buf[i] == '\n' || bufsize == i + 1)
-		{
-			buf[i] = 0;
-			return i;
-		}
-		i++;
-	}
-}
-
-#else
-
-#define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
-
-#endif
-
 /* connect() successed */
 
 static void
@@ -1394,12 +1384,7 @@ base64_encode (char *to, char *from, unsigned int len)
 static int
 http_read_line (int print_fd, int sok, char *buf, int len)
 {
-#ifdef WIN32
-	/* make sure waitline() uses recv() or it'll fail on win32 */
-	len = waitline (sok, buf, len, FALSE);
-#else
 	len = waitline (sok, buf, len, TRUE);
-#endif
 	if (len >= 1)
 	{
 		/* print the message out (send it to the parent process) */
@@ -1795,7 +1780,11 @@ server_connect (server *serv, char *hostname, int port, int no_login)
 	}
 #endif
 	serv->childpid = pid;
+#ifdef WIN32
+	serv->iotag = fe_input_add (serv->childread, FIA_READ|FIA_FD, server_read_child,
+#else
 	serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
+#endif
 										 serv);
 }
 
@@ -1835,10 +1824,10 @@ server_set_encoding (server *serv, char *new_encoding)
 			space[0] = 0;
 
 		/* server_inline() uses these flags */
-		if (!strcasecmp (serv->encoding, "CP1255") ||
-			 !strcasecmp (serv->encoding, "WINDOWS-1255"))
+		if (!g_ascii_strcasecmp (serv->encoding, "CP1255") ||
+			 !g_ascii_strcasecmp (serv->encoding, "WINDOWS-1255"))
 			serv->using_cp1255 = TRUE;
-		else if (!strcasecmp (serv->encoding, "IRC"))
+		else if (!g_ascii_strcasecmp (serv->encoding, "IRC"))
 			serv->using_irc = TRUE;
 	}
 }
diff --git a/src/common/servlist.c b/src/common/servlist.c
index 66bc8115..aa32aa4d 100644
--- a/src/common/servlist.c
+++ b/src/common/servlist.c
@@ -21,7 +21,10 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+
+#ifndef WIN32
 #include <unistd.h>
+#endif
 
 #include "xchat.h"
 #include <glib.h>
@@ -585,7 +588,7 @@ servlist_connect_by_netname (session *sess, char *network, gboolean join)
 	{
 		net = list->data;
 
-		if (strcasecmp (net->name, network) == 0)
+		if (g_ascii_strcasecmp (net->name, network) == 0)
 		{
 			servlist_connect (sess, net, join);
 			return 1;
@@ -730,7 +733,7 @@ servlist_net_find_from_server (char *server_name)
 		while (slist)
 		{
 			serv = slist->data;
-			if (strcasecmp (serv->hostname, server_name) == 0)
+			if (g_ascii_strcasecmp (serv->hostname, server_name) == 0)
 				return net;
 			slist = slist->next;
 		}
@@ -1015,7 +1018,7 @@ servlist_check_encoding (char *charset)
 	if (c)
 		c[0] = 0;
 
-	if (!strcasecmp (charset, "IRC")) /* special case */
+	if (!g_ascii_strcasecmp (charset, "IRC")) /* special case */
 	{
 		if (c)
 			c[0] = ' ';
@@ -1090,8 +1093,8 @@ servlist_save (void)
 			fprintf (fp, "J=%s\n", net->autojoin);
 		if (net->nickserv)
 			fprintf (fp, "B=%s\n", net->nickserv);
-		if (net->encoding && strcasecmp (net->encoding, "System") &&
-			 strcasecmp (net->encoding, "System default"))
+		if (net->encoding && g_ascii_strcasecmp (net->encoding, "System") &&
+			 g_ascii_strcasecmp (net->encoding, "System default"))
 		{
 			fprintf (fp, "E=%s\n", net->encoding);
 			if (!servlist_check_encoding (net->encoding))
diff --git a/src/common/ssl.c b/src/common/ssl.c
index a18ad47c..daa7416b 100644
--- a/src/common/ssl.c
+++ b/src/common/ssl.c
@@ -17,12 +17,12 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
+#include "inet.h"				  /* make it first to avoid macro redefinitions */
 #include <openssl/ssl.h>		  /* SSL_() */
 #include <openssl/err.h>		  /* ERR_() */
 #include <time.h>					  /* asctime() */
 #include <string.h>				  /* strncpy() */
 #include "ssl.h"					  /* struct cert_info */
-#include "inet.h"
 #include "../../config.h"		  /* HAVE_SNPRINTF */
 
 #ifndef HAVE_SNPRINTF
diff --git a/src/common/text.c b/src/common/text.c
index 6b111742..f8afc4b3 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -19,13 +19,16 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <ctype.h>
 #include <time.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+
+#ifndef WIN32
+#include <unistd.h>
 #include <sys/mman.h>
+#endif
 
 #include "xchat.h"
 #include <glib.h>
@@ -271,9 +274,15 @@ scrollback_load (session *sess)
 	char *text;
 	time_t stamp;
 	int lines;
+
+#ifdef WIN32
+	char *cleaned_text;
+	int cleaned_len;
+#else
 	char *map, *end_map;
 	struct stat statbuf;
 	const char *begin, *eol;
+#endif
 
 	if (sess->text_scrollback == SET_DEFAULT)
 	{
@@ -293,6 +302,7 @@ scrollback_load (session *sess)
 	if (fh == -1)
 		return;
 
+#ifndef WIN32
 	if (fstat (fh, &statbuf) < 0)
 		return;
 
@@ -301,7 +311,7 @@ scrollback_load (session *sess)
 		return;
 
 	end_map = map + statbuf.st_size;
-	
+
 	lines = 0;
 	begin = map;
 	while (begin < end_map)
@@ -314,11 +324,11 @@ scrollback_load (session *sess)
 			eol = end_map;
 
 		n_bytes = MIN (eol - begin, sizeof (buf) - 1);
-		
+
 		strncpy (buf, begin, n_bytes);
 
 		buf[n_bytes] = 0;
-		
+
 		if (buf[0] == 'T')
 		{
 			if (sizeof (time_t) == 4)
@@ -350,6 +360,45 @@ scrollback_load (session *sess)
 	}
 
 	munmap (map, statbuf.st_size);
+#else
+	lines = 0;
+	while (waitline (fh, buf, sizeof buf, FALSE) != -1)
+	{
+		if (buf[0] == 'T')
+		{
+			if (sizeof (time_t) == 4)
+				stamp = strtoul (buf + 2, NULL, 10);
+			else
+				stamp = strtoull (buf + 2, NULL, 10); /* just incase time_t is 64 bits */
+			text = strchr (buf + 3, ' ');
+			if (text)
+			{
+				text = strip_color (text + 1, -1, STRIP_COLOR);
+				cleaned_text = text_replace_non_bmp (text, -1, &cleaned_len);
+				if (cleaned_text != NULL)
+				{
+					g_free (text);
+					text = cleaned_text;
+				}
+				fe_print_text (sess, text, stamp);
+				g_free (text);
+			}
+			lines++;
+		}
+	}
+
+	sess->scrollwritten = lines;
+
+	if (lines)
+	{
+		text = ctime (&stamp);
+		text[24] = 0;	/* get rid of the \n */
+		snprintf (buf, sizeof (buf), "\n*\t%s %s\n\n", _("Loaded log from"), text);
+		fe_print_text (sess, buf, 0);
+		/*EMIT_SIGNAL (XP_TE_GENMSG, sess, "*", buf, NULL, NULL, NULL, 0);*/
+	}
+#endif
+
 	close (fh);
 }
 
@@ -637,6 +686,13 @@ get_stamp_str (char *fmt, time_t tim, char **ret)
 	}
 
 	len = strftime (dest, sizeof (dest), fmt, localtime (&tim));
+#ifdef WIN32
+	if (!len)
+	{
+		/* use failsafe format until a correct one is specified */
+		len = strftime (dest, sizeof (dest), "[%H:%M]", localtime (&tim));
+	}
+#endif
 	if (len)
 	{
 		if (prefs.utf8_locale)
@@ -812,6 +868,46 @@ iso_8859_1_to_utf8 (unsigned char *text, int len, gsize *bytes_written)
 	return res;
 }
 
+#ifdef WIN32
+/* replace characters outside of the Basic Multilingual Plane with
+ * replacement characters (0xFFFD) */
+char *
+text_replace_non_bmp (char *utf8_input, int input_length, glong *output_length)
+{
+	gunichar *ucs4_text;
+	gunichar suspect;
+	gchar *utf8_text;
+	glong ucs4_length;
+	glong index;
+
+	ucs4_text = g_utf8_to_ucs4_fast (utf8_input, input_length, &ucs4_length);
+
+	/* replace anything not in the Basic Multilingual Plane
+	 * (code points above 0xFFFF) with the replacement
+	 * character */
+	for (index = 0; index < ucs4_length; index++)
+	{
+		suspect = ucs4_text[index];
+		if ((suspect >= 0x1D173 && suspect <= 0x1D17A)
+			|| (suspect >= 0xE0001 && suspect <= 0xE007F))
+		{
+			ucs4_text[index] = 0xFFFD; /* replacement character */
+		}
+	}
+
+	utf8_text = g_ucs4_to_utf8 (
+		ucs4_text,
+		ucs4_length,
+		NULL,
+		output_length,
+		NULL
+	);
+	g_free (ucs4_text);
+
+	return utf8_text;
+}
+#endif
+
 char *
 text_validate (char **text, int *len)
 {
diff --git a/src/common/text.h b/src/common/text.h
index 150821ae..6d5ac03e 100644
--- a/src/common/text.h
+++ b/src/common/text.h
@@ -28,6 +28,9 @@ int pevent_load (char *filename);
 void pevent_make_pntevts (void);
 void text_emit (int index, session *sess, char *a, char *b, char *c, char *d);
 int text_emit_by_name (char *name, session *sess, char *a, char *b, char *c, char *d);
+#ifdef WIN32
+char *text_replace_non_bmp (char *utf8_input, int input_length, glong *output_length);
+#endif
 char *text_validate (char **text, int *len);
 int get_stamp_str (char *fmt, time_t tim, char **ret);
 void format_event (session *sess, int index, char **args, char *o, int sizeofo, unsigned int stripcolor_args);
diff --git a/src/common/thread.c b/src/common/thread.c
new file mode 100644
index 00000000..02b17cfb
--- /dev/null
+++ b/src/common/thread.c
@@ -0,0 +1,33 @@
+#include <fcntl.h>
+#include "thread.h"
+
+thread *
+thread_new (void)
+{
+	thread *th;
+
+	th = calloc (1, sizeof (*th));
+	if (!th)
+	{
+		return NULL;
+	}
+
+	if (_pipe (th->pipe_fd, 4096, _O_BINARY) == -1)
+	{
+		free (th);
+		return NULL;
+	}
+
+	return th;
+}
+
+int
+thread_start (thread *th, void *(*start_routine)(void *), void *arg)
+{
+	DWORD id;
+
+	CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, (DWORD *)&id));
+	th->threadid = id;
+
+	return 1;
+}
diff --git a/src/common/thread.h b/src/common/thread.h
new file mode 100644
index 00000000..7ca0f937
--- /dev/null
+++ b/src/common/thread.h
@@ -0,0 +1,10 @@
+#include <windows.h>
+
+typedef struct
+{
+	DWORD threadid;
+	int pipe_fd[2];
+} thread;
+
+thread *thread_new (void);
+int thread_start (thread *th, void *(*start_routine)(void *), void *arg);
diff --git a/src/common/url.c b/src/common/url.c
index b83732d1..9fa2d75c 100644
--- a/src/common/url.c
+++ b/src/common/url.c
@@ -82,7 +82,7 @@ url_find (char *urltext)
 {
 	int pos;
 
-	if (tree_find (url_tree, urltext, (tree_cmp_func *)strcasecmp, NULL, &pos))
+	if (tree_find (url_tree, urltext, (tree_cmp_func *)g_ascii_strcasecmp, NULL, &pos))
 		return 1;
 	return 0;
 }
@@ -117,7 +117,7 @@ url_add (char *urltext, int len)
 	}
 
 	if (!url_tree)
-		url_tree = tree_new ((tree_cmp_func *)strcasecmp, NULL);
+		url_tree = tree_new ((tree_cmp_func *)g_ascii_strcasecmp, NULL);
 
 	size = tree_size (url_tree);
 	/* 0 is unlimited */
@@ -186,7 +186,7 @@ url_check_word (char *word, int len)
 		{
 			int j;
 
-			/* This is pretty much strncasecmp(). */
+			/* This is pretty much g_ascii_strncasecmp(). */
 			for (j = 0; j < l; j++)
 			{
 				unsigned char c = word[j];
@@ -238,7 +238,7 @@ url_check_word (char *word, int len)
 				const unsigned char *p = &word[len - l];
 				int j;
 
-				/* This is pretty much strncasecmp(). */
+				/* This is pretty much g_ascii_strncasecmp(). */
 				for (j = 0; j < l; j++)
 				{
 					if (tolower(p[j]) != suffix[i].s[j])
diff --git a/src/common/util.c b/src/common/util.c
index 5a0ab6c5..fb4cd23e 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -16,26 +16,32 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
+#define WANTSOCKET
+#include "inet.h"				/* make it first to avoid macro redefinitions */
+
 #define __APPLE_API_STRICT_CONFORMANCE
 
 #define _FILE_OFFSET_BITS 64
 #include <stdio.h>
-#include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+
 #ifdef WIN32
 #include <sys/timeb.h>
 #include <process.h>
+#include <io.h>
+#include "../dirent/dirent-win32.h"
 #else
-#include <sys/types.h>
+#include <unistd.h>
 #include <pwd.h>
 #include <sys/time.h>
 #include <sys/utsname.h>
+#include <dirent.h>
 #endif
+
 #include <fcntl.h>
-#include <dirent.h>
 #include <errno.h>
 #include "xchat.h"
 #include "xchatc.h"
@@ -44,9 +50,6 @@
 #include "util.h"
 #include "../../config.h"
 
-#define WANTSOCKET
-#include "inet.h"
-
 #if defined (USING_FREEBSD) || defined (__APPLE__)
 #include <sys/sysctl.h>
 #endif
@@ -280,7 +283,7 @@ nocasestrstr (const char *s, const char *wanted)
 
 	if (len == 0)
 		return (char *)s;
-	while (rfc_tolower(*s) != rfc_tolower(*wanted) || strncasecmp (s, wanted, len))
+	while (rfc_tolower(*s) != rfc_tolower(*wanted) || g_ascii_strncasecmp (s, wanted, len))
 		if (*s++ == '\0')
 			return (char *)NULL;
 	return (char *)s;
@@ -383,6 +386,28 @@ waitline (int sok, char *buf, int bufsize, int use_recv)
 	}
 }
 
+#ifdef WIN32
+/* waitline2 using win32 file descriptor and glib instead of _read. win32 can't _read() sok! */
+int
+waitline2 (GIOChannel *source, char *buf, int bufsize)
+{
+	int i = 0;
+	int len;
+
+	while (1)
+	{
+		if (g_io_channel_read (source, &buf[i], 1, &len) != G_IO_ERROR_NONE)
+			return -1;
+		if (buf[i] == '\n' || bufsize == i + 1)
+		{
+			buf[i] = 0;
+			return i;
+		}
+		i++;
+	}
+}
+#endif
+
 /* checks for "~" in a file and expands */
 
 char *
@@ -624,30 +649,110 @@ get_mhz (void)
 	return 0;	/* fails on Win9x */
 }
 
+int
+get_cpu_arch (void)
+{
+	SYSTEM_INFO si;
+
+	GetSystemInfo (&si);
+
+	if (si.wProcessorArchitecture == 9)
+	{
+		return 64;
+	}
+	else
+	{
+		return 86;
+	}
+}
+
 char *
 get_cpu_str (void)
 {
 	static char verbuf[64];
-	OSVERSIONINFO osvi;
-	SYSTEM_INFO si;
+	static char winver[20];
+	OSVERSIONINFOEX osvi;
 	double mhz;
 
-	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
 	GetVersionEx (&osvi);
-	GetSystemInfo (&si);
+
+	switch (osvi.dwMajorVersion)
+	{
+		case 5:
+			switch (osvi.dwMinorVersion)
+			{
+				case 1:
+					strcpy (winver, "XP");
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcpy (winver, "XP x64 Edition");
+					}
+					else
+					{
+						if (GetSystemMetrics(SM_SERVERR2) == 0)
+						{
+							strcpy (winver, "Server 2003");
+						}
+						else
+						{
+							strcpy (winver, "Server 2003 R2");
+						}
+					}
+					break;
+			}
+			break;
+		case 6:
+			switch (osvi.dwMinorVersion)
+			{
+				case 0:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcpy (winver, "Vista");
+					}
+					else
+					{
+						strcpy (winver, "Server 2008");
+					}
+					break;
+				case 1:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcpy (winver, "7");
+					}
+					else
+					{
+						strcpy (winver, "Server 2008 R2");
+					}
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcpy (winver, "8");
+					}
+					else
+					{
+						strcpy (winver, "8 Server");
+					}
+					break;
+			}
+			break;
+	}
 
 	mhz = get_mhz ();
 	if (mhz)
 	{
 		double cpuspeed = ( mhz > 1000 ) ? mhz / 1000 : mhz;
 		const char *cpuspeedstr = ( mhz > 1000 ) ? "GHz" : "MHz";
-		sprintf (verbuf, "Windows %ld.%ld [i%d86/%.2f%s]",
-					osvi.dwMajorVersion, osvi.dwMinorVersion, si.wProcessorLevel, 
-					cpuspeed, cpuspeedstr);
-	} else
-		sprintf (verbuf, "Windows %ld.%ld [i%d86]",
-			osvi.dwMajorVersion, osvi.dwMinorVersion, si.wProcessorLevel);
-
+		sprintf (verbuf, "Windows %s [%.2f%s]",	winver, cpuspeed, cpuspeedstr);
+	}
+	else
+	{
+		sprintf (verbuf, "Windows %s", winver);
+	}
+	
 	return verbuf;
 }
 
@@ -840,7 +945,7 @@ typedef struct
 static int
 country_compare (const void *a, const void *b)
 {
-	return strcasecmp (a, ((domain_t *)b)->code);
+	return g_ascii_strcasecmp (a, ((domain_t *)b)->code);
 }
 
 static const domain_t domain[] =
@@ -1727,3 +1832,55 @@ safe_strcpy (char *dest, const char *src, int bytes_left)
 		}
 	}
 }
+
+void
+canonalize_key (char *key)
+{
+	char *pos, token;
+
+	for (pos = key; (token = *pos) != 0; pos++)
+	{
+		if (token != '_' && (token < '0' || token > '9') && (token < 'A' || token > 'Z') && (token < 'a' || token > 'z'))
+		{
+			*pos = '_';
+		}
+		else
+		{
+			*pos = tolower(token);
+		}
+	}
+}
+
+int
+portable_mode ()
+{
+#ifdef WIN32
+	if ((_access( "portable-mode", 0 )) != -1)
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+#else
+	return 0;
+#endif
+}
+
+int
+xtray_mode ()
+{
+#ifdef WIN32
+	if ((_access( "plugins/xtray.dll", 0 )) != -1)
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+#else
+	return 0;
+#endif
+}
diff --git a/src/common/util.h b/src/common/util.h
index fce45def..82d74366 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -43,6 +43,12 @@ int strip_color2 (const char *src, int len, char *dst, int flags);
 int strip_hidden_attribute (char *src, char *dst);
 char *errorstring (int err);
 int waitline (int sok, char *buf, int bufsize, int);
+#ifdef WIN32
+int waitline2 (GIOChannel *source, char *buf, int bufsize);
+int get_cpu_arch (void);
+#else
+#define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
+#endif
 unsigned long make_ping_time (void);
 void move_file_utf8 (char *src_dir, char *dst_dir, char *fname, int dccpermissions);
 int mkdir_utf8 (char *dir);
@@ -50,5 +56,8 @@ int token_foreach (char *str, char sep, int (*callback) (char *str, void *ud), v
 guint32 str_hash (const char *key);
 guint32 str_ihash (const unsigned char *key);
 void safe_strcpy (char *dest, const char *src, int bytes_left);
+void canonalize_key (char *key);
+int portable_mode ();
+int xtray_mode ();
 
 #endif
diff --git a/src/common/xchat-plugin.h b/src/common/xchat-plugin.h
index 30b19295..1b7da8fb 100644
--- a/src/common/xchat-plugin.h
+++ b/src/common/xchat-plugin.h
@@ -137,6 +137,21 @@ struct _xchat_plugin
 	     int flags);
 	void (*xchat_free) (xchat_plugin *ph,
 	    void *ptr);
+	int (*xchat_pluginpref_set_str) (xchat_plugin *ph,
+		const char *var,
+		const char *value);
+	int (*xchat_pluginpref_get_str) (xchat_plugin *ph,
+		const char *var,
+		char *dest);
+	int (*xchat_pluginpref_set_int) (xchat_plugin *ph,
+		const char *var,
+		int value);
+	int (*xchat_pluginpref_get_int) (xchat_plugin *ph,
+		const char *var);
+	int (*xchat_pluginpref_delete) (xchat_plugin *ph,
+		const char *var);
+	int (*xchat_pluginpref_list) (xchat_plugin *ph,
+		char *dest);
 };
 #endif
 
@@ -292,6 +307,32 @@ void
 xchat_free (xchat_plugin *ph,
 	    void *ptr);
 
+int
+xchat_pluginpref_set_str (xchat_plugin *ph,
+		const char *var,
+		const char *value);
+
+int
+xchat_pluginpref_get_str (xchat_plugin *ph,
+		const char *var,
+		char *dest);
+
+int
+xchat_pluginpref_set_int (xchat_plugin *ph,
+		const char *var,
+		int value);
+int
+xchat_pluginpref_get_int (xchat_plugin *ph,
+		const char *var);
+
+int
+xchat_pluginpref_delete (xchat_plugin *ph,
+		const char *var);
+
+int
+xchat_pluginpref_list (xchat_plugin *ph,
+		char *dest);
+
 #if !defined(PLUGIN_C) && defined(WIN32)
 #ifndef XCHAT_PLUGIN_HANDLE
 #define XCHAT_PLUGIN_HANDLE (ph)
@@ -326,6 +367,12 @@ xchat_free (xchat_plugin *ph,
 #define xchat_send_modes ((XCHAT_PLUGIN_HANDLE)->xchat_send_modes)
 #define xchat_strip ((XCHAT_PLUGIN_HANDLE)->xchat_strip)
 #define xchat_free ((XCHAT_PLUGIN_HANDLE)->xchat_free)
+#define xchat_pluginpref_set_str ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_set_str)
+#define xchat_pluginpref_get_str ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_get_str)
+#define xchat_pluginpref_set_int ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_set_int)
+#define xchat_pluginpref_get_int ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_get_int)
+#define xchat_pluginpref_delete ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_delete)
+#define xchat_pluginpref_list ((XCHAT_PLUGIN_HANDLE)->xchat_pluginpref_list)
 #endif
 
 #ifdef __cplusplus
diff --git a/src/common/xchat.c b/src/common/xchat.c
index afac9a0e..845f262b 100644
--- a/src/common/xchat.c
+++ b/src/common/xchat.c
@@ -22,14 +22,16 @@
 #include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <unistd.h>
 
 #define WANTSOCKET
 #include "inet.h"
 
-#ifndef WIN32
+#ifdef WIN32
+#include <windows.h>
+#else
 #include <sys/wait.h>
 #include <signal.h>
+#include <unistd.h>
 #endif
 
 #include "xchat.h"
@@ -590,6 +592,7 @@ static char defaultconf_commands[] =
 	"NAME DMSG\n"			"CMD msg =%2 &3\n\n"\
 	"NAME EXIT\n"			"CMD quit\n\n"\
 	"NAME GREP\n"			"CMD lastlog -r &2\n\n"\
+	"NAME IGNALL\n"			"CMD ignore %2!*@* ALL\n\n"\
 	"NAME J\n"				"CMD join &2\n\n"\
 	"NAME KILL\n"			"CMD quote KILL %2 :&3\n\n"\
 	"NAME LEAVE\n"			"CMD part &2\n\n"\
@@ -899,11 +902,55 @@ xchat_execv (char * const argv[])
 #endif
 }
 
+#ifdef WIN32
+static void
+xchat_restore_window (HWND xchat_window)
+{
+	/* ShowWindow (xchat_window, SW_RESTORE); another way, but works worse */
+	SendMessage (xchat_window, WM_SYSCOMMAND, SC_RESTORE, 0);
+	SetForegroundWindow (xchat_window);
+}
+
+BOOL CALLBACK
+enum_windows_impl (HWND current_window, LPARAM lParam)
+{
+	TCHAR window_name[10];
+	TCHAR module_path[1024];
+	ZeroMemory (&window_name, sizeof (window_name));
+
+	if (!current_window)
+	{
+		return TRUE;
+	}
+
+	GetWindowText (current_window, window_name, 10);
+	if (stricmp (window_name, "xchat-wdk") == 0)
+	{
+		/* use a separate if block, this way we don't have to call GetWindowModuleFileName() for each hit */
+		ZeroMemory (&module_path, sizeof (module_path));
+		GetWindowModuleFileName (current_window, module_path, sizeof (module_path));
+
+		if (strstr (module_path, "xchat.exe"))	/* We've found it, stop */
+		{
+			xchat_restore_window (current_window);
+			return FALSE;
+		}
+	}
+
+	return TRUE;								/* Keep searching */
+
+}
+#endif
+
 int
 main (int argc, char *argv[])
 {
 	int ret;
-	
+
+#ifdef WIN32
+	HANDLE mutex;
+#endif
+
 	srand (time (0));	/* CL: do this only once! */
 
 #ifdef SOCKS
@@ -920,6 +967,34 @@ main (int argc, char *argv[])
 
 	load_config ();
 
+#ifdef WIN32
+	if (prefs.gui_one_instance && !portable_mode ())
+	{
+		DWORD error;
+
+		mutex = CreateMutex (NULL, TRUE, "Local\xchat");
+		error = GetLastError ();
+
+		if (error == ERROR_ALREADY_EXISTS || mutex == NULL)
+		{
+			/* restoring the XChat window from the tray via the taskbar icon
+			 * only works correctly when X-Tray is used, but it's not a big deal
+			 * since you can only minimize XChat to tray via the taskbar if you
+			 * use X-Tray*/
+			if (xtray_mode ())
+			{
+				/* FindWindow() doesn't support wildcards so we check all the open windows */
+				EnumWindows (enum_windows_impl, NULL);
+				return 0;
+			}
+			else
+			{
+				return 1;
+			}
+		}
+	}
+#endif
+
 #ifdef USE_LIBPROXY
 	libproxy_factory = px_proxy_factory_new();
 #endif
@@ -945,6 +1020,11 @@ main (int argc, char *argv[])
 
 #ifdef WIN32
 	WSACleanup ();
+
+	if (prefs.gui_one_instance && !portable_mode ())
+	{
+		CloseHandle (mutex);
+	}
 #endif
 
 	return 0;
diff --git a/src/common/xchat.h b/src/common/xchat.h
index 6e31d7c5..85c20186 100644
--- a/src/common/xchat.h
+++ b/src/common/xchat.h
@@ -13,7 +13,7 @@
 #endif
 
 #ifndef HAVE_VSNPRINTF
-#define vsnprintf g_vsnprintf
+#define vsnprintf _vsnprintf
 #endif
 
 #ifdef USE_DEBUG
@@ -41,8 +41,8 @@ void *xchat_realloc (char *old, int len, char *file, int line);
 
 #ifdef __EMX__						  /* for o/s 2 */
 #define OFLAGS O_BINARY
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
+#define g_ascii_strcasecmp stricmp
+#define g_ascii_strncasecmp strnicmp
 #define PATH_MAX MAXPATHLEN
 #define FILEPATH_LEN_MAX MAXPATHLEN
 #endif
@@ -54,7 +54,7 @@ void *xchat_realloc (char *old, int len, char *file, int line);
 
 #ifdef WIN32						/* for win32 */
 #define OFLAGS O_BINARY
-#define sleep(t) _sleep(t*1000)
+#define sleep(t) Sleep(t*1000)
 #include <direct.h>
 #define	F_OK	0
 #define	X_OK	1
@@ -113,8 +113,16 @@ struct xchatprefs
 	char awayreason[256];
 	char quitreason[256];
 	char partreason[256];
+#ifdef WIN32
+	char font_normal[4 * FONTNAMELEN + 1];
+	char font_main[FONTNAMELEN + 1];
+	char font_alternative[3 * FONTNAMELEN + 1];
+#else
 	char font_normal[FONTNAMELEN + 1];
+#endif
 	char doubleclickuser[256];
+	char gui_license[64];
+	char spell_langs[64];
 	char sounddir[PATHLEN + 1];
 	char soundcmd[PATHLEN + 1];
 	char background[PATHLEN + 1];
@@ -152,6 +160,7 @@ struct xchatprefs
 
 	int gui_pane_left_size;
 	int gui_pane_right_size;
+	int gui_pane_right_size_min;
 
 	int gui_ulist_pos;
 	int tab_pos;
@@ -178,6 +187,9 @@ struct xchatprefs
 	int gui_usermenu;
 	int gui_join_dialog;
 	int gui_quit_dialog;
+#ifdef WIN32
+	int gui_one_instance;
+#endif
 	int dialog_left;
 	int dialog_top;
 	int dialog_width;
@@ -205,6 +217,9 @@ struct xchatprefs
 	unsigned int wallops;
 	unsigned int skipmotd;
 	unsigned int autorejoin;
+	unsigned int autocopy_text;
+	unsigned int autocopy_stamp;
+	unsigned int autocopy_color;
 	unsigned int colorednicks;
 	unsigned int chanmodebuttons;
 	unsigned int userlistbuttons;
@@ -292,7 +307,12 @@ struct xchatprefs
 	unsigned int wait_on_exit;
 	unsigned int confmode;
 	unsigned int utf8_locale;
+#ifdef WIN32
 	unsigned int identd;
+	unsigned int emoticons;
+	unsigned int tab_icons;
+	unsigned int tab_xp;
+#endif
 
 	unsigned int ctcp_number_limit;	/*flood */
 	unsigned int ctcp_time_limit;	/*seconds of floods */
@@ -306,6 +326,11 @@ struct xchatprefs
 		This is so that we continue using internal defaults (which can
 		change in the next release) until the user edits them. */
 	unsigned int save_pevents:1;
+	unsigned int text_search_case_match;
+	unsigned int text_search_backward;
+	unsigned int text_search_highlight_all;
+	unsigned int text_search_follow;
+	unsigned int text_search_regexp;
 };
 
 /* Session types */