summary refs log tree commit diff stats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/checksum/checksum.c264
-rw-r--r--plugins/checksum/makefile.mak18
-rw-r--r--plugins/dns/dns.c329
-rw-r--r--plugins/dns/makefile.mak22
-rw-r--r--plugins/dns/thread.c33
-rw-r--r--plugins/dns/thread.h11
-rw-r--r--plugins/doat/doat.c80
-rw-r--r--plugins/doat/makefile.mak18
-rw-r--r--plugins/ewc/COPYING502
-rw-r--r--plugins/ewc/ewc.c231
-rw-r--r--plugins/ewc/makefile.mak18
-rw-r--r--plugins/exec/exec.c138
-rw-r--r--plugins/exec/makefile.mak18
-rw-r--r--plugins/fishlim/INSTALL16
-rw-r--r--plugins/fishlim/LICENSE21
-rw-r--r--plugins/fishlim/Makefile40
-rw-r--r--plugins/fishlim/README44
-rw-r--r--plugins/fishlim/bool.h5
-rw-r--r--plugins/fishlim/fish.c192
-rw-r--r--plugins/fishlim/fish.h42
-rw-r--r--plugins/fishlim/irc.c112
-rw-r--r--plugins/fishlim/irc.h43
-rw-r--r--plugins/fishlim/keystore.c209
-rw-r--r--plugins/fishlim/keystore.h42
-rw-r--r--plugins/fishlim/makefile.mak30
-rw-r--r--plugins/fishlim/misc.c54
-rw-r--r--plugins/fishlim/misc.h36
-rw-r--r--plugins/fishlim/plugin_xchat.c290
-rw-r--r--plugins/fishlim/plugin_xchat.h31
-rw-r--r--plugins/fishlim/test.c91
-rw-r--r--plugins/gtkpref/gtkpref.c69
-rw-r--r--plugins/gtkpref/makefile.mak18
-rw-r--r--plugins/lua/lua.c1882
-rw-r--r--plugins/lua/makefile.mak20
-rw-r--r--plugins/makefile.mak71
-rw-r--r--plugins/mpcinfo/functions.c167
-rw-r--r--plugins/mpcinfo/makefile.mak18
-rw-r--r--plugins/mpcinfo/mp3Info.c361
-rw-r--r--plugins/mpcinfo/mpcInfo.c149
-rw-r--r--plugins/mpcinfo/oggInfo.c122
-rw-r--r--plugins/mpcinfo/theme.c136
-rw-r--r--plugins/nonbmp/makefile.mak18
-rw-r--r--plugins/nonbmp/nonbmp.c87
-rw-r--r--plugins/perl/makefile-512.mak40
-rw-r--r--plugins/perl/makefile-514.mak42
-rw-r--r--plugins/perl/perl.c11
-rw-r--r--plugins/plugin20.html139
-rw-r--r--plugins/python/makefile.mak25
-rw-r--r--plugins/python/python.c10
-rw-r--r--plugins/tcl/makefile.mak22
-rw-r--r--plugins/tcl/tclplugin.c2
-rw-r--r--plugins/upd/makefile.mak18
-rw-r--r--plugins/upd/upd.c226
-rw-r--r--plugins/winamp/makefile.mak18
-rw-r--r--plugins/winamp/winamp.c189
-rw-r--r--plugins/winsys/makefile.mak18
-rw-r--r--plugins/winsys/winsys.cpp415
-rw-r--r--plugins/wmpa/ReadMe.txt70
-rw-r--r--plugins/wmpa/StdAfx.cpp8
-rw-r--r--plugins/wmpa/StdAfx.h62
-rw-r--r--plugins/wmpa/makefile.mak53
-rw-r--r--plugins/wmpa/res/wmpa.rc213
-rw-r--r--plugins/wmpa/resource.h22
-rw-r--r--plugins/wmpa/wmpa.cpp212
-rw-r--r--plugins/wmpa/wmpa.def15
-rw-r--r--plugins/wmpa/wmpa.h61
-rw-r--r--plugins/wmpa/wmpa.icobin0 -> 4286 bytes
-rw-r--r--plugins/wmpa/wmpa.odl44
-rw-r--r--plugins/wmpa/wmpa.rc207
-rw-r--r--plugins/wmpa/wmpa.sln20
-rw-r--r--plugins/wmpa/wmpa.vcxproj231
-rw-r--r--plugins/wmpa/wmpa.vcxproj.filters172
-rw-r--r--plugins/wmpa/wmpadialog.cpp375
-rw-r--r--plugins/wmpa/wmpadialog.h91
-rw-r--r--plugins/wmpa/wmpcdrom.cpp37
-rw-r--r--plugins/wmpa/wmpcdrom.h39
-rw-r--r--plugins/wmpa/wmpcdromcollection.cpp45
-rw-r--r--plugins/wmpa/wmpcdromcollection.h39
-rw-r--r--plugins/wmpa/wmpclosedcaption.cpp75
-rw-r--r--plugins/wmpa/wmpclosedcaption.h40
-rw-r--r--plugins/wmpa/wmpcontrols.cpp123
-rw-r--r--plugins/wmpa/wmpcontrols.h52
-rw-r--r--plugins/wmpa/wmpdvd.cpp52
-rw-r--r--plugins/wmpa/wmpdvd.h38
-rw-r--r--plugins/wmpa/wmperror.cpp45
-rw-r--r--plugins/wmpa/wmperror.h40
-rw-r--r--plugins/wmpa/wmperroritem.cpp50
-rw-r--r--plugins/wmpa/wmperroritem.h37
-rw-r--r--plugins/wmpa/wmpmedia.cpp167
-rw-r--r--plugins/wmpa/wmpmedia.h50
-rw-r--r--plugins/wmpa/wmpmediacollection.cpp133
-rw-r--r--plugins/wmpa/wmpmediacollection.h50
-rw-r--r--plugins/wmpa/wmpnetwork.cpp233
-rw-r--r--plugins/wmpa/wmpnetwork.h60
-rw-r--r--plugins/wmpa/wmpplayer4.cpp321
-rw-r--r--plugins/wmpa/wmpplayer4.h104
-rw-r--r--plugins/wmpa/wmpplayerapplication.cpp39
-rw-r--r--plugins/wmpa/wmpplayerapplication.h36
-rw-r--r--plugins/wmpa/wmpplaylist.cpp132
-rw-r--r--plugins/wmpa/wmpplaylist.h50
-rw-r--r--plugins/wmpa/wmpplaylistarray.cpp35
-rw-r--r--plugins/wmpa/wmpplaylistarray.h38
-rw-r--r--plugins/wmpa/wmpplaylistcollection.cpp82
-rw-r--r--plugins/wmpa/wmpplaylistcollection.h44
-rw-r--r--plugins/wmpa/wmpsettings.cpp193
-rw-r--r--plugins/wmpa/wmpsettings.h55
-rw-r--r--plugins/wmpa/wmpstringcollection.cpp32
-rw-r--r--plugins/wmpa/wmpstringcollection.h34
-rw-r--r--plugins/wmpa/xchat-plugin.cpp590
-rw-r--r--plugins/wmpa/xchat-plugin.h368
-rw-r--r--plugins/xchat-plugin.h47
-rw-r--r--plugins/xdcc/makefile.mak18
-rw-r--r--plugins/xdcc/xdcc.c6
-rw-r--r--plugins/xsasl/makefile.mak18
-rw-r--r--plugins/xsasl/xsasl.c314
-rw-r--r--plugins/xtray/bitmaps/sd.bmpbin0 -> 32824 bytes
-rw-r--r--plugins/xtray/callbacks.cpp734
-rw-r--r--plugins/xtray/callbacks.h37
-rw-r--r--plugins/xtray/icons/banned.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/chan_msg.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/disconnected.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/highlight-1-3.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/highlight.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/kicked.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/priv_msg-1-2-2.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/sd.icobin0 -> 24358 bytes
-rw-r--r--plugins/xtray/icons/server_notice.icobin0 -> 1406 bytes
-rw-r--r--plugins/xtray/icons/xchat.icobin0 -> 25670 bytes
-rw-r--r--plugins/xtray/makefile.mak37
-rw-r--r--plugins/xtray/resource.h47
-rw-r--r--plugins/xtray/resource.rc309
-rw-r--r--plugins/xtray/sdAlerts.cpp109
-rw-r--r--plugins/xtray/sdAlerts.h26
-rw-r--r--plugins/xtray/sdTray.cpp207
-rw-r--r--plugins/xtray/sdTray.h39
-rw-r--r--plugins/xtray/utility.cpp607
-rw-r--r--plugins/xtray/utility.h55
-rw-r--r--plugins/xtray/xchat.cpp320
-rw-r--r--plugins/xtray/xchat.h32
-rw-r--r--plugins/xtray/xtray.cpp219
-rw-r--r--plugins/xtray/xtray.h77
141 files changed, 15739 insertions, 6 deletions
diff --git a/plugins/checksum/checksum.c b/plugins/checksum/checksum.c
new file mode 100644
index 00000000..79f64982
--- /dev/null
+++ b/plugins/checksum/checksum.c
@@ -0,0 +1,264 @@
+/* XChat-WDK
+ * Copyright (c) 2010-2012 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <openssl/sha.h>
+
+#include "xchat-plugin.h"
+
+#define BUFSIZE 32768
+#define DEFAULT_LIMIT 256									/* default size is 256 MiB */
+
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef stat64
+#define stat64 _stat64
+#endif
+
+static xchat_plugin *ph;									/* plugin handle */
+static const char name[] = "Checksum";
+static const char desc[] = "Calculate checksum for DCC file transfers";
+static const char version[] = "3.0";
+
+/* Use of OpenSSL SHA256 interface: http://adamlamers.com/?p=5 */
+static void
+sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65])
+{
+	int i;
+	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+	{
+		sprintf (outputBuffer + (i * 2), "%02x", hash[i]);
+	}
+	outputBuffer[64] = 0;
+}
+
+static void
+sha256 (char *string, char outputBuffer[65])
+{
+	int i;
+	unsigned char hash[SHA256_DIGEST_LENGTH];
+	SHA256_CTX sha256;
+
+	SHA256_Init (&sha256);
+	SHA256_Update (&sha256, string, strlen (string));
+	SHA256_Final (hash, &sha256);
+
+	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+	{
+		sprintf (outputBuffer + (i * 2), "%02x", hash[i]);
+	}
+	outputBuffer[64] = 0;
+}
+
+static int
+sha256_file (char *path, char outputBuffer[65])
+{
+	int bytesRead;
+	unsigned char *buffer;
+	unsigned char hash[SHA256_DIGEST_LENGTH];
+	SHA256_CTX sha256;
+
+	FILE *file = fopen (path, "rb");
+	if (!file)
+	{
+		return -534;
+	}
+
+	SHA256_Init (&sha256);
+	buffer = malloc (BUFSIZE);
+	bytesRead = 0;
+
+	if (!buffer)
+	{
+		return ENOMEM;
+	}
+
+	while ((bytesRead = fread (buffer, 1, BUFSIZE, file)))
+	{
+		SHA256_Update (&sha256, buffer, bytesRead);
+	}
+
+	SHA256_Final (hash, &sha256);
+	sha256_hash_string (hash, outputBuffer);
+
+	fclose (file);
+	free (buffer);
+	return 0;
+}
+
+static void
+set_limit (char* size)
+{
+	int buffer = atoi (size);
+
+	if (buffer > 0 && buffer < INT_MAX)
+	{
+		if (xchat_pluginpref_set_int (ph, "limit", buffer))
+		{
+			xchat_printf (ph, "File size limit has successfully been set to: %d MiB\n", buffer);
+		}
+		else
+		{
+			xchat_printf (ph, "File access error while saving!\n");
+		}
+	}
+	else
+	{
+		xchat_printf (ph, "Invalid input!\n");
+	}
+}
+
+static int
+get_limit ()
+{
+	int size = xchat_pluginpref_get_int (ph, "limit");
+
+	if (size <= -1 || size >= INT_MAX)
+	{
+		return DEFAULT_LIMIT;
+	}
+	else
+	{
+		return size;
+	}
+}
+
+static void
+print_limit ()
+{
+	xchat_printf (ph, "File size limit for checksums: %d MiB", get_limit ());
+}
+
+static int
+dccrecv_cb (char *word[], void *userdata)
+{
+	int result;
+	struct stat64 buffer;									/* buffer for storing file info */
+	char sum[65];											/* buffer for checksum */
+
+	result = stat64 (word[2], &buffer);
+	if (result == 0)										/* stat returns 0 on success */
+	{
+		if (buffer.st_size <= (unsigned long long) get_limit () * 1048576)
+		{
+			sha256_file (word[2], sum);						/* word[2] is the full filename */
+			/* try to print the checksum in the privmsg tab of the sender */
+			xchat_set_context (ph, xchat_find_context (ph, NULL, word[3]));
+			xchat_printf (ph, "SHA-256 checksum for %s (local):  %s\n", word[1], sum);
+		}
+		else
+		{
+			xchat_set_context (ph, xchat_find_context (ph, NULL, word[3]));
+			xchat_printf (ph, "SHA-256 checksum for %s (local):  (size limit reached, no checksum calculated, you can increase it with /CHECKSUM INC)\n", word[1]);
+		}
+	}
+	else
+	{
+		xchat_printf (ph, "File access error!\n");
+	}
+
+	return XCHAT_EAT_NONE;
+}
+
+static int
+dccoffer_cb (char *word[], void *userdata)
+{
+	int result;
+	struct stat64 buffer;									/* buffer for storing file info */
+	char sum[65];											/* buffer for checksum */
+
+	result = stat64 (word[3], &buffer);
+	if (result == 0)										/* stat returns 0 on success */
+	{
+		if (buffer.st_size <= (unsigned long long) get_limit () * 1048576)
+		{
+			sha256_file (word[3], sum);						/* word[3] is the full filename */
+			xchat_commandf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): %s", word[2], word[1], sum);
+		}
+		else
+		{
+			xchat_set_context (ph, xchat_find_context (ph, NULL, word[3]));
+			xchat_printf (ph, "quote PRIVMSG %s :SHA-256 checksum for %s (remote): (size limit reached, no checksum calculated)", word[2], word[1]);
+		}
+	}
+	else
+	{
+		xchat_printf (ph, "File access error!\n");
+	}
+
+	return XCHAT_EAT_NONE;
+}
+
+static void
+checksum (char *word[], void *userdata)
+{
+	if (!stricmp ("GET", word[2]))
+	{
+		print_limit ();
+	}
+	else if (!stricmp ("SET", word[2]))
+	{
+		set_limit (word[3]);
+	}
+	else
+	{
+		xchat_printf (ph, "Usage: /CHECKSUM GET|INC|DEC\n");
+		xchat_printf (ph, "  GET - print the maximum file size (in MiB) to be hashed\n");
+		xchat_printf (ph, "  SET <filesize> - set the maximum file size (in MiB) to be hashed\n");
+	}
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	/* this is required for the very first run */
+	if (xchat_pluginpref_get_int (ph, "limit") == -1)
+	{
+		xchat_pluginpref_set_int (ph, "limit", DEFAULT_LIMIT);
+	}
+
+	xchat_hook_command (ph, "CHECKSUM", XCHAT_PRI_NORM, checksum, "Usage: /CHECKSUM GET|SET", 0);
+	xchat_hook_print (ph, "DCC RECV Complete", XCHAT_PRI_NORM, dccrecv_cb, NULL);
+	xchat_hook_print (ph, "DCC Offer", XCHAT_PRI_NORM, dccoffer_cb, NULL);
+
+	xchat_printf (ph, "%s plugin loaded\n", name);
+	return 1;
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
diff --git a/plugins/checksum/makefile.mak b/plugins/checksum/makefile.mak
new file mode 100644
index 00000000..ec8e0455
--- /dev/null
+++ b/plugins/checksum/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: checksum.obj checksum.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcchecksum.dll /def:checksum.def checksum.obj 

+

+checksum.def:

+	echo EXPORTS > checksum.def

+	echo xchat_plugin_init >> checksum.def

+	echo xchat_plugin_deinit >> checksum.def

+

+checksum.obj: checksum.c makefile.mak

+	cl $(CFLAGS) /I.. checksum.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/dns/dns.c b/plugins/dns/dns.c
new file mode 100644
index 00000000..2bf58195
--- /dev/null
+++ b/plugins/dns/dns.c
@@ -0,0 +1,329 @@
+/* XChat Win32 DNS Plugin
+ * Copyright (C) 2003-2004 Peter Zelezny.
+ * Copyright (C) 2012 Berke Viktor.
+ *
+ * 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
+ */
+/*
+ * Requires MS Visual Studio and IPV6 headers to compile (run nmake).
+ * Compiling with gcc (mingw) will fail due to missing gai_strerror.
+ */
+
+#define DNS_VERSION "2.4"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#define USE_IPV6
+
+#ifdef WIN32
+#ifdef USE_IPV6
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <winsock2.h>
+#endif
+#else
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#endif
+
+#include "xchat-plugin.h"
+#include "thread.h"
+
+#define HELP "Usage: DNS <nickname|hostname|numerical address>\n"
+#define HEAD "\0034[DNS]\017\t"
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+#define MAX_HOSTNAME 128
+
+static xchat_plugin *ph;
+static thread *active_thread = NULL;
+
+
+static int
+waitline (void *source, char *buf, int bufsize)
+{
+	int i = 0;
+	int len;
+
+	while(1)
+	{
+		len = 1;
+		/* we can't read() here, due to glib's giowin32 */
+		if(ph->xchat_read_fd(ph, source, buf + i, &len) != 0)
+			return -1;
+		if(buf[i] == '\n' || bufsize == i + 1)
+		{
+			buf[i] = 0;
+			return i;
+		}
+		i++;
+	}
+}
+
+static void *
+thread_function (void *ud)
+{
+#ifdef USE_IPV6
+	struct addrinfo *ent;
+	struct addrinfo *cur;
+	struct addrinfo hints;
+#else
+	struct hostent *ent;
+#endif
+	thread *th = ud;
+	int fd = th->pipe_fd[PIPE_WRITE];
+	int ret;
+	char ipstring[MAX_HOSTNAME];
+	char reverse[MAX_HOSTNAME];
+//	int i;
+
+	active_thread = th;
+
+#ifdef USE_IPV6
+	memset (&hints, 0, sizeof (hints));
+	hints.ai_family = PF_UNSPEC; /* support ipv6 and ipv4 */
+	hints.ai_flags = AI_CANONNAME;
+//	hints.ai_socktype = SOCK_STREAM;
+
+	ret = getaddrinfo (th->userdata, NULL, &hints, &ent);
+	if (ret != 0)
+	{
+		sprintf (ipstring, "1%d\n", ret);	/* failed */
+		write (fd, ipstring, strlen (ipstring));
+//		Sleep (3000);
+		active_thread = NULL;
+		return 0;
+	}
+
+//	i = 0;
+	cur = ent;
+	while (cur)
+	{
+		/* find the numeric IP number */
+		ipstring[0] = 0;
+		getnameinfo (cur->ai_addr, cur->ai_addrlen,
+						 ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST);
+
+		if (cur->ai_canonname)
+		{
+			/* force reverse lookup if canonname & ipstring are the same */
+			if (/*i == 0 &&*/ strcmp (cur->ai_canonname, ipstring) == 0)
+				goto lamecode;
+		}
+
+		if (cur->ai_canonname)
+		{
+			write (fd, "0", 1);
+			write (fd, ipstring, strlen (ipstring));
+			write (fd, "\n", 1);
+			write (fd, cur->ai_canonname, strlen (cur->ai_canonname));
+		} else
+		{
+lamecode:
+	//		ret = 1;
+	//		if (i == 0)
+			{
+				/* reverse lookup */
+				reverse[0] = 0;
+				ret = getnameinfo (cur->ai_addr, cur->ai_addrlen,
+							 reverse, sizeof (reverse), NULL, 0, NI_NAMEREQD);
+			}
+
+			write (fd, "0", 1);
+			write (fd, ipstring, strlen (ipstring));
+
+			write (fd, "\n", 1);
+			if (ret == 0)
+				write (fd, reverse, strlen (reverse));
+		}
+		write (fd, "\n", 1);
+
+//		i++;
+		cur = cur->ai_next;
+	}
+
+	/* tell the parent we're done */
+	write (fd, "2\n", 2);
+	freeaddrinfo (ent);
+
+#else
+	ent = gethostbyname (th->userdata);
+	if (ent)
+	{
+		write (fd, "0", 1);
+		write (fd, ent->h_name, strlen (ent->h_name));
+		write (fd, "\n", 1);
+		write (fd, ent->h_name, strlen (ent->h_name));
+		write (fd, "\n", 1);
+		write (fd, "2\n", 2);
+	} else
+	{
+		write (fd, "10\n", 1);
+	}
+#endif
+
+//	Sleep (3000);
+	active_thread = NULL;	/* race condition, better than nothing */
+
+	return 0;
+}
+
+static int
+dns_close_pipe (int fd)
+{
+	close (fd);
+	return 0;
+}
+
+/* read messages comming from the child (through the pipe) */
+
+static int
+dns_read_cb (int fd, int flags, thread *th, void *source)
+{
+	char buf[512];
+	char buf2[512];
+
+	while (waitline (source, buf, sizeof (buf)))
+	{
+		switch (buf[0])
+		{
+		case '0':		/* got data to show */
+			waitline (source, buf2, sizeof (buf2));
+			if (buf2[0] == 0)
+				xchat_printf(ph, HEAD"\002Numerical\002: %s\n", buf + 1);
+			else
+				xchat_printf(ph, HEAD"\002Canonical\002: %s \002Numerical\002: %s\n", buf2, buf + 1);
+			return 1;
+
+		case '1':		/* failed */
+			xchat_printf(ph, HEAD"Lookup failed. %s\n", gai_strerrorA (atoi (buf + 1)));
+
+		case '2':		/* done */
+		//	close (th->pipe_fd[PIPE_WRITE]);
+		//	close (th->pipe_fd[PIPE_READ]);
+			xchat_hook_timer(ph, 3000, dns_close_pipe, (void *)th->pipe_fd[PIPE_WRITE]);
+			xchat_hook_timer(ph, 4000, dns_close_pipe, (void *)th->pipe_fd[PIPE_READ]);
+			free (th->userdata); 	/* hostname strdup'ed */
+			free (th);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/* find hostname from nickname (search the userlist, current chan only) */
+
+static char *
+find_nick_host (char *nick)
+{
+	xchat_list *list;
+	char *at;
+	const char *host;
+
+	list = xchat_list_get (ph, "users");
+	if (!list)
+		return NULL;
+
+	while (xchat_list_next (ph, list))
+	{
+		if (stricmp (nick, xchat_list_str (ph, list, "nick")) == 0)
+		{
+			host = xchat_list_str (ph, list, "host");
+			if (host)
+			{
+				at = strrchr (host, '@');
+				if (at)
+					return at + 1;
+			}
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+static int
+dns_cmd_cb (char *word[], char *word_eol[], void *ud)
+{
+	thread *th;
+	char *nickhost;
+
+	if (!word[2][0])
+	{
+		xchat_print (ph, HELP);
+		return XCHAT_EAT_ALL;
+	}
+
+	th = thread_new ();
+	if (th)
+	{
+		nickhost = find_nick_host (word[2]);
+		if (nickhost)
+		{
+			xchat_printf (ph, HEAD"Looking up %s (%s)...\n", nickhost, word[2]);
+			th->userdata = strdup (nickhost);
+		} else
+		{
+			xchat_printf (ph, HEAD"Looking up %s...\n", word[2]);
+			th->userdata = strdup (word[2]);
+		}
+
+		if (thread_start (th, thread_function, th))
+		{
+			xchat_hook_fd(ph, th->pipe_fd[PIPE_READ],
+							XCHAT_FD_READ | XCHAT_FD_EXCEPTION | XCHAT_FD_NOTSOCKET,
+							(void *)dns_read_cb, th);
+
+		}
+	}
+
+	return XCHAT_EAT_ALL;
+}
+
+int
+xchat_plugin_deinit (xchat_plugin *plugin_handle)
+{
+	while (active_thread)	/* children will set this var to NULL soon... */
+	{
+		Sleep (1000);
+	}
+	xchat_printf (ph, "DNS plugin unloaded\n");
+	return 1;
+}
+
+int
+xchat_plugin_init
+				(xchat_plugin *plugin_handle, char **plugin_name,
+				char **plugin_desc, char **plugin_version, char *arg)
+{
+	/* we need to save this for use with any xchat_* functions */
+	ph = plugin_handle;
+
+	*plugin_name = "DNS";
+	*plugin_desc = "Threaded IPv4/6 DNS Command";
+	*plugin_version = DNS_VERSION;
+
+	xchat_hook_command(ph, "DNS", XCHAT_PRI_LOW, dns_cmd_cb, HELP, 0);
+	xchat_printf (ph, "DNS plugin loaded\n");
+
+	return 1;       /* return 1 for success */
+}
diff --git a/plugins/dns/makefile.mak b/plugins/dns/makefile.mak
new file mode 100644
index 00000000..384e6be1
--- /dev/null
+++ b/plugins/dns/makefile.mak
@@ -0,0 +1,22 @@
+include "..\..\src\makeinc.mak"

+

+DNS_OBJECTS = \

+dns.obj \

+thread.obj

+

+all: $(DNS_OBJECTS) dns.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcdns.dll /def:dns.def $(DNS_OBJECTS)

+

+dns.def:

+	echo EXPORTS > dns.def

+	echo xchat_plugin_init >> dns.def

+	echo xchat_plugin_deinit >> dns.def

+

+.c.obj:

+	$(CC) $(CFLAGS) $(GLIB) /I.. /c $<

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/dns/thread.c b/plugins/dns/thread.c
new file mode 100644
index 00000000..02b17cfb
--- /dev/null
+++ b/plugins/dns/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/plugins/dns/thread.h b/plugins/dns/thread.h
new file mode 100644
index 00000000..1ec6932d
--- /dev/null
+++ b/plugins/dns/thread.h
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+typedef struct
+{
+	DWORD threadid;
+	int pipe_fd[2];
+	void *userdata;
+} thread;
+
+thread *thread_new (void);
+int thread_start (thread *th, void *(*start_routine)(void *), void *arg);
diff --git a/plugins/doat/doat.c b/plugins/doat/doat.c
new file mode 100644
index 00000000..e03507f1
--- /dev/null
+++ b/plugins/doat/doat.c
@@ -0,0 +1,80 @@
+/* This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/wtfpl/COPYING or http://lwsitu.com/xchat/COPYING
+ * for more details. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;
+
+static int
+parse_command( char *word[], char *word_eol[], void *userdata ) {
+	char *channel = NULL, *server = NULL, *token = NULL;
+/*	char *save_ptr1 = NULL;*/
+	char *str1 = NULL;
+	char *delimiter = NULL;
+
+	xchat_context *ctx = NULL;
+
+	if( word[2] != NULL && word[3] != NULL ) {
+		for( str1 = word[2]; ; str1 = NULL ) {
+/*			token = strtok_r( str1, ",", &save_ptr1 );*/
+			token = strtok( str1, "," );
+/*			printf( "token: %s\n", token );*/
+
+			if( token == NULL ) {
+				break;
+			}
+
+			channel = malloc( strlen( token ) + 1 );
+			strcpy( channel, token );
+				
+			delimiter = strchr( channel, '/' );
+
+			server = NULL;
+			if( delimiter != NULL ) {
+				*delimiter = '\0';
+				server = delimiter + 1;
+			}
+
+/*			printf( "channel[%s] server[%s]\n", channel, server );*/
+
+			if( (ctx = xchat_find_context( ph, server, channel ) ) != NULL ) {
+				if( xchat_set_context( ph, ctx ) ) {
+					xchat_command( ph, word_eol[3] );
+				}
+			}
+
+			free( channel );
+		}
+	}
+	return XCHAT_EAT_XCHAT;
+}
+
+int
+xchat_plugin_init( xchat_plugin * plugin_handle, char **plugin_name,
+	char **plugin_desc, char **plugin_version, char *arg ) {
+
+	ph = plugin_handle;
+	*plugin_name = "Do At";
+	*plugin_version = "1.0";
+	*plugin_desc = "Perform an arbitrary command on multiple channels";
+
+	xchat_hook_command( ph, "doat", XCHAT_PRI_NORM, parse_command, "DOAT [channel,list,/network] [command], perform a command on multiple contexts", NULL );
+
+	xchat_print (ph, "Do At plugin loaded\n");
+
+	return 1;
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_print (ph, "Do At plugin unloaded\n");
+	return 1;
+}
diff --git a/plugins/doat/makefile.mak b/plugins/doat/makefile.mak
new file mode 100644
index 00000000..960cae27
--- /dev/null
+++ b/plugins/doat/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: doat.obj doat.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcdoat.dll /def:doat.def doat.obj

+

+doat.def:

+	echo EXPORTS > doat.def

+	echo xchat_plugin_init >> doat.def

+	echo xchat_plugin_deinit >> doat.def

+

+doat.obj: doat.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. doat.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/ewc/COPYING b/plugins/ewc/COPYING
new file mode 100644
index 00000000..4362b491
--- /dev/null
+++ b/plugins/ewc/COPYING
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/plugins/ewc/ewc.c b/plugins/ewc/ewc.c
new file mode 100644
index 00000000..78e7e9ac
--- /dev/null
+++ b/plugins/ewc/ewc.c
@@ -0,0 +1,231 @@
+/*

+EasyWinampControl - A Winamp "What's playing" plugin for Xchat

+Copyright (C) Yann HAMON & contributors

+

+This library is free software; you can redistribute it and/or

+modify it under the terms of the GNU Lesser General Public

+License as published by the Free Software Foundation; either

+version 2.1 of the License, or (at your option) any later version.

+

+This library 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

+Lesser General Public License for more details.

+

+You should have received a copy of the GNU Lesser General Public

+License along with this library; if not, write to the Free Software

+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+*/

+

+#include "xchat-plugin.h"

+#include <windows.h>

+

+static xchat_plugin *ph;   /* plugin handle */

+static int enable = 1;

+

+// For example, circularstrstr("winamp", "pwi", 3) would return 5 (the index of p)

+int circularstrstr(char* a, char* b, int nb)

+{

+  int equal = 1;

+  int length;

+  int pos=-1;

+  int i, j;

+

+  length = strlen(a);

+

+  for (i=0; i<length && pos == -1; ++i) {

+    equal = 1;

+    for (j=0; j<nb;j++) {

+      if (a[(i+j)%length] != b[j])

+        equal = 0;

+    }

+    if (equal == 1)

+      pos = i;

+  }

+

+  return pos;

+}

+

+void GetCurrentSongsName(HWND hwndWinamp, char* title, int titlesize)

+{

+  int pos;

+  char *title2;

+  int i, j=0;

+  int length;

+  char *p;

+

+  GetWindowText(hwndWinamp, title, titlesize);

+  length = strlen(title);

+

+  if ((pos = circularstrstr(title, "- Winamp ***", 12)) != -1) {

+    // The option "scroll song title in taskbar" is on

+    title2 = (char*) malloc (titlesize*sizeof(char));

+

+    for (i=(pos+12)%length; i!=pos; i=(i+1)%length)

+      title2[j++] = title[i];

+

+    title2[j] = '\0';

+

+    p = title2;

+    while (p<title2+titlesize && *p != '.')

+      p++;

+    p+=2; // Delete the . and the following white space

+

+    strcpy(title, p);

+    free(title2);

+  }

+  else {

+    p = title;

+    while (p<title+titlesize && *p != '.')

+      p++;

+    p+=2; // Delete the . and the following white space

+    if (p<title+titlesize)

+      strncpy(title, p, titlesize-(p-title));

+

+    // Delete the trailing "- winamp"

+    p = title + titlesize - 1;

+    while (p>title && *p != '-') p--;

+    *p = '\0';

+  }

+}

+

+

+// Controlling winamp

+static int wcmd_cb(char *word[], char *word_eol[], void *userdata)

+{

+  // Everything's here : http://winamp.com/nsdn/winamp2x/dev/sdk/api.php

+  // The previous url seems dead, see http://forums.winamp.com/showthread.php?threadid=180297

+  HWND hwndWinamp = NULL;

+

+  if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL) {

+    xchat_print(ph, "Winamp's window not found - Is winamp really running?\n");

+  }

+  else {

+    if (strcmp(word[1], "") == 0)

+      xchat_print(ph, "Usage: wcmd [command]\n");

+    else if (strcmp(word[2], "next") == 0) {

+      xchat_print(ph, "Loading next song...\n");

+      SendMessage (hwndWinamp, WM_COMMAND, 40048, 0);

+    }

+    else if (strcmp(word[2], "prev") == 0) {

+      xchat_print(ph, "Loading previous song...\n");

+      SendMessage (hwndWinamp, WM_COMMAND, 40044, 0);

+    }

+    else if (strcmp(word[2], "play") == 0) {

+      xchat_print(ph, "Playin'...\n");

+      SendMessage (hwndWinamp, WM_COMMAND, 40045, 0);

+    }

+    else if (strcmp(word[2], "stop") == 0) {

+      xchat_print(ph, "Winamp stopped!...\n");

+      SendMessage (hwndWinamp, WM_COMMAND, 40047, 0);

+    }

+    else if (strcmp(word[2], "pause") == 0) {

+      SendMessage (hwndWinamp, WM_COMMAND, 40046, 0);

+    }

+  }

+

+  return XCHAT_EAT_ALL;

+}

+

+

+// Display current song

+static int wp_cb(char *word[], char *word_eol[], void *userdata)

+{

+  HWND hwndWinamp = NULL;

+  int bitrate, length, elapsed, minutes, seconds, eminutes, eseconds, samplerate, nbchannels;

+  char elapsedtime[7];

+  char totaltime[7];

+  char this_title[1024];

+

+  if ((hwndWinamp = FindWindow("Winamp v1.x",NULL)) == NULL)

+    xchat_print(ph, "Winamp's window not found - Is winamp really running?\n");

+  else {

+    //Winamp's running

+    // Seems buggy when winamp2's agent is running, and winamp not (or winamp3) -> crashes xchat.

+    SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)125);

+

+    if ((samplerate = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)126)) == 0) {

+      xchat_print(ph, "Could not get current song's samplerate... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+    if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) {

+      xchat_print(ph, "Could not get current song's bitrate... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+    if ((nbchannels = SendMessage(hwndWinamp, WM_USER, (WPARAM)2, (LPARAM)126)) == 0) {

+      xchat_print(ph, "Could not get the number of channels... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+    if ((length = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)105)) == 0) {

+      // Could be buggy when streaming audio or video, returned length is unexpected;

+      // How to detect is Winamp is streaming, and display ??:?? in that case?

+      xchat_print(ph, "Could not get current song's length... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+    else {

+      minutes = length/60;

+      seconds = length%60;

+

+      if (seconds>9)

+        wsprintf(totaltime, "%d:%d", minutes, seconds);

+      else

+        wsprintf(totaltime, "%d:0%d", minutes, seconds);

+    }

+    if ((elapsed = SendMessage(hwndWinamp, WM_USER, (WPARAM)0, (LPARAM)105)) == 0) {

+      xchat_print(ph, "Could not get current song's elapsed time... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+    else {

+      eminutes = (elapsed/1000)/60;   /* kinda stupid sounding, but e is for elapsed */

+      eseconds = (elapsed/1000)%60;

+

+      if (eseconds>9)

+        wsprintf(elapsedtime, "%d:%d", eminutes, eseconds);

+      else

+        wsprintf(elapsedtime, "%d:0%d", eminutes, eseconds);

+    }

+

+    if ((bitrate = SendMessage(hwndWinamp, WM_USER, (WPARAM)1, (LPARAM)126)) == 0) {

+      xchat_print(ph, "Could not get current song's bitrate... !?\n");

+      return XCHAT_EAT_ALL;

+    }

+

+    GetCurrentSongsName(hwndWinamp, this_title, 1024);

+

+    xchat_commandf(ph, "dispcurrsong %d %d %d %s %s %s", samplerate, bitrate, nbchannels, elapsedtime, totaltime, this_title);

+  }

+

+  return XCHAT_EAT_ALL;   /* eat this command so xchat and other plugins can't process it */

+}

+

+

+

+int xchat_plugin_init(xchat_plugin *plugin_handle,

+                      char **plugin_name,

+                      char **plugin_desc,

+                      char **plugin_version,

+                      char *arg)

+{

+  /* we need to save this for use with any xchat_* functions */

+  ph = plugin_handle;

+

+  *plugin_name = "EasyWinampControl";

+  *plugin_desc = "Some commands to remotely control winamp";

+  *plugin_version = "1.2";

+

+  xchat_hook_command(ph, "wp", XCHAT_PRI_NORM, wp_cb,

+                    "Usage: wp", 0);

+

+  xchat_hook_command(ph, "wcmd", XCHAT_PRI_NORM, wcmd_cb,

+                    "Usage: wcmd [play|pause|stop|prev|next]", 0);

+

+  xchat_print(ph, "EasyWinampControl plugin loaded\n");

+

+  return 1;       /* return 1 for success */

+}

+

+int xchat_plugin_deinit(void)

+{

+  xchat_print(ph, "EasyWinampControl plugin unloaded\n");

+  return 1;

+}

diff --git a/plugins/ewc/makefile.mak b/plugins/ewc/makefile.mak
new file mode 100644
index 00000000..9b9f21c1
--- /dev/null
+++ b/plugins/ewc/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: ewc.obj ewc.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcewc.dll /def:ewc.def ewc.obj

+

+ewc.def:

+	echo EXPORTS > ewc.def

+	echo xchat_plugin_init >> ewc.def

+	echo xchat_plugin_deinit >> ewc.def

+

+ewc.obj: ewc.c makefile.mak

+	cl $(CFLAGS) ewc.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/exec/exec.c b/plugins/exec/exec.c
new file mode 100644
index 00000000..22f38814
--- /dev/null
+++ b/plugins/exec/exec.c
@@ -0,0 +1,138 @@
+/* XChat-WDK
+ * Copyright (c) 2011 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <windows.h>
+#include <time.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+static const char name[] = "Exec";
+static const char desc[] = "Execute commands inside XChat";
+static const char version[] = "1.1";
+
+static int
+run_command (char *word[], char *word_eol[], void *userdata)
+{
+	char commandLine[1024];
+	char buffer[4096];
+	DWORD dwRead = 0;
+	DWORD dwLeft = 0;
+	DWORD dwAvail = 0;
+	time_t start;
+	double timeElapsed;
+
+	HANDLE readPipe;
+	HANDLE writePipe;
+	STARTUPINFO sInfo; 
+	PROCESS_INFORMATION pInfo; 
+	SECURITY_ATTRIBUTES secattr; 
+
+	ZeroMemory (&secattr, sizeof (secattr));
+	secattr.nLength = sizeof (secattr);
+	secattr.bInheritHandle = TRUE;
+
+	if (strlen (word[2]) > 0)
+	{
+		strcpy (commandLine, "cmd.exe /c ");
+
+		if (!stricmp("-O", word[2]))
+		{
+			/*strcat (commandLine, word_eol[3]);*/
+			xchat_printf (ph, "Printing Exec output to others is not supported yet.\n");
+			return XCHAT_EAT_XCHAT;
+		}
+		else
+		{
+			strcat (commandLine, word_eol[2]);
+		}
+
+		CreatePipe (&readPipe, &writePipe, &secattr, 0); /* might be replaced with MyCreatePipeEx */
+
+		ZeroMemory (&sInfo, sizeof (sInfo));
+		ZeroMemory (&pInfo, sizeof (pInfo));
+		sInfo.cb = sizeof (sInfo);
+		sInfo.dwFlags = STARTF_USESTDHANDLES;
+		sInfo.hStdInput = NULL;
+		sInfo.hStdOutput = writePipe;
+		sInfo.hStdError = writePipe;
+
+		CreateProcess (0, commandLine, 0, 0, TRUE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, 0, 0, &sInfo, &pInfo);
+		CloseHandle (writePipe);
+
+		start = time (0);
+		while (PeekNamedPipe (readPipe, buffer, 1, &dwRead, &dwAvail, &dwLeft) && timeElapsed < 10)
+		{
+			if (dwRead)
+			{
+				if (ReadFile (readPipe, buffer, sizeof (buffer) - 1, &dwRead, NULL) && dwRead != 0 )
+				{
+					/* avoid garbage */
+					buffer[dwRead] = '\0';
+					xchat_printf (ph, "%s", buffer);
+				}
+			}
+			else
+			{
+				/* this way we'll more likely get full lines */
+				SleepEx (100, TRUE);
+			}
+			timeElapsed = difftime (time (0), start);
+		}
+	}
+
+	/* display a newline to separate things */
+	xchat_printf (ph, "\n");
+
+	if (timeElapsed >= 10)
+	{
+		xchat_printf (ph, "Command took too much time to run, execution aborted.\n");
+	}
+
+	CloseHandle (readPipe);
+	CloseHandle (pInfo.hProcess);
+	CloseHandle (pInfo.hThread);
+
+	return XCHAT_EAT_XCHAT;
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	xchat_hook_command (ph, "EXEC", XCHAT_PRI_NORM, run_command, "Usage: /EXEC [-O] - execute commands inside XChat", 0);
+	xchat_printf (ph, "%s plugin loaded\n", name);
+
+	return 1;       /* return 1 for success */
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
diff --git a/plugins/exec/makefile.mak b/plugins/exec/makefile.mak
new file mode 100644
index 00000000..d2153faf
--- /dev/null
+++ b/plugins/exec/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: exec.obj exec.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcexec.dll /def:exec.def exec.obj

+

+exec.def:

+	echo EXPORTS > exec.def

+	echo xchat_plugin_init >> exec.def

+	echo xchat_plugin_deinit >> exec.def

+

+exec.obj: exec.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. exec.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/fishlim/INSTALL b/plugins/fishlim/INSTALL
new file mode 100644
index 00000000..d0d61ff8
--- /dev/null
+++ b/plugins/fishlim/INSTALL
@@ -0,0 +1,16 @@
+
+Install dependencies (on Debian/Ubuntu):
+
+    sudo apt-get install  build-essential libglib2.0-dev libssl-dev
+
+
+Build the plugin with:
+
+    make
+
+
+Install with:
+
+    sudo make install
+
+
diff --git a/plugins/fishlim/LICENSE b/plugins/fishlim/LICENSE
new file mode 100644
index 00000000..427f2631
--- /dev/null
+++ b/plugins/fishlim/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) 2010-2011 Samuel Lidén Borell <samuel@slbdata.se>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/plugins/fishlim/Makefile b/plugins/fishlim/Makefile
new file mode 100644
index 00000000..3f0e93d2
--- /dev/null
+++ b/plugins/fishlim/Makefile
@@ -0,0 +1,40 @@
+
+OURCFLAGS = -Wall -Wextra -Wno-unused-parameter -std=c99 -pedantic `pkg-config --cflags glib-2.0 libcrypto` -DG_DISABLE_DEPRECATED=1 -fPIC $(CFLAGS)
+#OURLINKFLAGS = `pkg-config --libs glib-2.0 libcrypto` -shared -fPIC -Wl,-z,defs $(CFLAGS) $(LDFLAGS)
+OURLINKFLAGS = `pkg-config --libs glib-2.0 libcrypto` $(CFLAGS) $(LDFLAGS)
+
+BASE_OBJECTS = irc.o fish.o keystore.o misc.o
+PLUGIN_OBJECTS = $(BASE_OBJECTS) plugin_xchat.o
+TEST_OBJECTS = $(BASE_OBJECTS) test.o
+
+all: fishlim.so test
+
+fish.o: fish.h keystore.h misc.h
+irc.o: irc.h
+keystore.o: keystore.h irc.h fish.h misc.h plugin_xchat.h
+misc.o: misc.h
+test.o: fish.h
+plugin_xchat.o: fish.h irc.h keystore.h plugin_xchat.h
+
+.c.o:
+	$(CC) $(OURCFLAGS) -c $< -o $@
+
+fishlim.so: $(PLUGIN_OBJECTS)
+	$(CC) -shared $(OURLINKFLAGS) $(PLUGIN_OBJECTS) -o $@
+
+test: $(TEST_OBJECTS)
+	$(CC) $(TEST_OBJECTS) -o $@ $(OURLINKFLAGS)
+
+
+.PHONY: all clean distclean install uninstall
+clean:
+	-$(RM) -f $(PLUGIN_OBJECTS) $(TEST_OBJECTS) fishlim.so test
+distclean: clean
+
+install: fishlim.so
+	install -d $(DESTDIR)/usr/lib/xchat/plugins/
+	install -m 644 fishlim.so $(DESTDIR)/usr/lib/xchat/plugins/
+uninstall:
+	rm $(DESTDIR)/usr/lib/xchat/plugins/fishlim.so
+
+
diff --git a/plugins/fishlim/README b/plugins/fishlim/README
new file mode 100644
index 00000000..4f315b44
--- /dev/null
+++ b/plugins/fishlim/README
@@ -0,0 +1,44 @@
+
+
+                                FiSHLiM
+
+                       http://fishlim.kodafritt.se/
+
+
+FiSHLiM is an XChat plugin for FiSH IRC encryption. It's my attempt at making
+a simple, lightweight and secure plugin for this encryption protocol.
+
+For installation instructions, see the INSTALL file.
+
+
+Features
+--------
+
+Working:
+  * Sending/receiving messages
+  * Topic decryption
+  * Using unecrypted keys / keys without a password from blow.ini
+  * Pure protocol-level filtering (works with highlighting, nick coloring etc)
+  * Partially encrypted messages (i.e. prefixed with nickname by a bouncer)
+
+Not working:
+  * Key exchange
+  * Password-protected key storage
+  * Topic encryption
+  * Remote exploitation (hopefully!)
+
+
+Commands
+--------
+
+/setkey  [nick or #channel]  password
+
+    Sets the encryption key for the nick or channel to password. The keys
+    are stored in the configuration file in ~/.xchat2/blow.ini
+
+
+/delkey  nick-or-#channel
+
+    Deletes the given nick or channel from the configuration file.
+
+
diff --git a/plugins/fishlim/bool.h b/plugins/fishlim/bool.h
new file mode 100644
index 00000000..2c8ddde4
--- /dev/null
+++ b/plugins/fishlim/bool.h
@@ -0,0 +1,5 @@
+/* stdbool.h replacement for MSVC */
+#define false 0
+#define true 1
+#define bool _Bool
+typedef int _Bool;
diff --git a/plugins/fishlim/fish.c b/plugins/fishlim/fish.c
new file mode 100644
index 00000000..cb977d7f
--- /dev/null
+++ b/plugins/fishlim/fish.c
@@ -0,0 +1,192 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/blowfish.h>
+
+#include "keystore.h"
+#include "fish.h"
+
+#define IB 64
+static const char fish_base64[64] = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const signed char fish_unbase64[256] = {
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB,IB,IB,
+//      !  "  #  $  %  &  '  (    )  *  +  ,  -  .  /
+    IB,IB,IB,IB,IB,IB,IB,IB,  IB,IB,IB,IB,IB,IB, 0, 1,
+//   0  1  2  3  4  5  6  7    8  9  :  ;  <  =  >  ?
+     2, 3, 4, 5, 6, 7, 8, 9,  10,11,IB,IB,IB,IB,IB,IB,
+//   @  A  B  C  D  E  F  G    H  I  J  K  L  M  N  O
+    IB,38,39,40,41,42,43,44,  45,46,47,48,49,50,51,52,
+//   P  Q  R  S  T  U  V  W    X  Y  Z  [  \  ]  ^  _
+    53,54,55,56,57,58,59,60,  61,62,63,IB,IB,IB,IB,IB,
+//   `  a  b  c  d  e  f  g    h  i  j  k  l  m  n  o
+    IB,12,13,14,15,16,17,18,  19,20,21,22,23,24,25,26,
+//   p  q  r  s  t  u  v  w    x  y  z  {  |  }  ~  <del>
+    27,28,29,30,31,32,33,34,  35,36,37,IB,IB,IB,IB,IB,
+};
+
+#define GET_BYTES(dest, source) do { \
+    *((dest)++) = ((source) >> 24) & 0xFF; \
+    *((dest)++) = ((source) >> 16) & 0xFF; \
+    *((dest)++) = ((source) >> 8) & 0xFF; \
+    *((dest)++) = (source) & 0xFF; \
+} while (0);
+
+
+char *fish_encrypt(const char *key, size_t keylen, const char *message) {
+    BF_KEY bfkey;
+    size_t messagelen;
+    size_t i;
+    int j;
+    char *encrypted;
+    char *end;
+    unsigned char bit;
+    unsigned char word;
+    unsigned char d;
+    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
+    
+    messagelen = strlen(message);
+    if (messagelen == 0) return NULL;
+    encrypted = malloc(((messagelen-1)/8)*12 + 12 + 1); // each 8-byte block becomes 12 bytes
+    end = encrypted;
+    if (!encrypted) return NULL;
+     
+    while (*message) {
+        // Read 8 bytes (a Blowfish block)
+        BF_LONG binary[2] = { 0, 0 };
+        unsigned char c;
+        for (i = 0; i < 8; i++) {
+            c = message[i];
+            binary[i >> 2] |= c << 8*(3 - (i&3));
+            if (c == '\0') break;
+        }
+        message += 8;
+        
+        // Encrypt block
+        BF_encrypt(binary, &bfkey);
+        
+        // Emit FiSH-BASE64
+        bit = 0;
+        word = 1;
+        for (j = 0; j < 12; j++) {
+            d = fish_base64[(binary[word] >> bit) & 63];
+            *(end++) = d;
+            bit += 6;
+            if (j == 5) {
+                bit = 0;
+                word = 0;
+            }
+        }
+        
+        // Stop if a null terminator was found
+        if (c == '\0') break;
+    }
+    *end = '\0';
+    return encrypted;
+}
+
+
+char *fish_decrypt(const char *key, size_t keylen, const char *data) {
+    BF_KEY bfkey;
+    size_t i;
+    char *decrypted;
+    char *end;
+    unsigned char bit;
+    unsigned char word;
+    unsigned char d;
+    BF_set_key(&bfkey, keylen, (const unsigned char*)key);
+    
+    decrypted = malloc(strlen(data)+1);
+    end = decrypted;
+    if (!decrypted) return NULL;
+    
+    while (*data) {
+        // Convert from FiSH-BASE64
+        BF_LONG binary[2] = { 0, 0 };
+        bit = 0;
+        word = 1;
+        for (i = 0; i < 12; i++) {
+            d = fish_unbase64[(const unsigned char)*(data++)];
+            if (d == IB) goto decrypt_end;
+            binary[word] |= d << bit;
+            bit += 6;
+            if (i == 5) {
+                bit = 0;
+                word = 0;
+            }
+        }
+        
+        // Decrypt block
+        BF_decrypt(binary, &bfkey);
+        
+        // Copy to buffer
+        GET_BYTES(end, binary[0]);
+        GET_BYTES(end, binary[1]);
+    }
+    
+  decrypt_end:
+    *end = '\0';
+    return decrypted;
+}
+
+/**
+ * Encrypts a message (see fish_decrypt). The key is searched for in the
+ * key store.
+ */
+char *fish_encrypt_for_nick(const char *nick, const char *data) {
+    char *key;
+    char *encrypted;
+
+    // Look for key
+    key = keystore_get_key(nick);
+    if (!key) return NULL;
+    
+    // Encrypt
+    encrypted = fish_encrypt(key, strlen(key), data);
+    
+    free(key);
+    return encrypted;
+}
+
+/**
+ * Decrypts a message (see fish_decrypt). The key is searched for in the
+ * key store.
+ */
+char *fish_decrypt_from_nick(const char *nick, const char *data) {
+    char *key;
+    char *decrypted;
+    // Look for key
+    key = keystore_get_key(nick);
+    if (!key) return NULL;
+    
+    // Decrypt
+    decrypted = fish_decrypt(key, strlen(key), data);
+    
+    free(key);
+    return decrypted;
+}
+
+
diff --git a/plugins/fishlim/fish.h b/plugins/fishlim/fish.h
new file mode 100644
index 00000000..d4057a7b
--- /dev/null
+++ b/plugins/fishlim/fish.h
@@ -0,0 +1,42 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef FISH_H
+#define FISH_H
+
+#ifdef _MSC_VER
+#include "bool.h"
+#else
+#include <stdbool.h>
+#endif
+#include <stddef.h>
+
+char *fish_encrypt(const char *key, size_t keylen, const char *message);
+char *fish_decrypt(const char *key, size_t keylen, const char *data);
+char *fish_encrypt_for_nick(const char *nick, const char *data);
+char *fish_decrypt_from_nick(const char *nick, const char *data);
+
+#endif
+
+
diff --git a/plugins/fishlim/irc.c b/plugins/fishlim/irc.c
new file mode 100644
index 00000000..a96c4c91
--- /dev/null
+++ b/plugins/fishlim/irc.c
@@ -0,0 +1,112 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "irc.h"
+
+/**
+ * Parses an IRC message. The words array should contain the message splitted
+ * at spaces. The prefix and command is extracted from the message, and
+ * parameters_offset is set to the index of the first parameter.
+ */
+bool irc_parse_message(const char *words[],
+                       const char **prefix, const char **command,
+                       size_t *parameters_offset) {
+    size_t w = 1;
+    if (prefix) *prefix = NULL;
+    if (command) *command = NULL;
+    
+    // See if the message starts with a prefix (sender user)
+    if (words[w][0] == ':') {
+        if (prefix) *prefix = &words[w][1];
+        w++;
+    }
+    
+    // Check command
+    if (words[w][0] == '\0') return false;
+    if (command) *command = words[w];
+    w++;
+    
+    *parameters_offset = w;
+    return true;
+}
+
+
+/**
+ * Finds the nick part of a "IRC prefix", which can have any
+ * of the following forms:
+ *
+ *     nick
+ *     nick@host
+ *     nick!ident
+ *     nick!ident@host
+ */
+char *irc_prefix_get_nick(const char *prefix) {
+    const char *end;
+    char *nick;
+    size_t length;
+    
+    if (!prefix) return NULL;
+    
+    // Find end of nick
+    end = prefix;
+    while (*end != '\0' && *end != '!' && *end != '@') end++;
+    
+    // Allocate string
+    length = end - prefix;
+    nick = malloc(length+1);
+    if (!nick) return NULL;
+    
+    // Copy to string
+    memcpy(nick, prefix, length);
+    nick[length] = '\0';
+    return nick;
+}
+
+
+/**
+ * Compares two nick names. Return 0 if equal. Otherwise the return value is
+ * less than zero if a is less than b or greater than zero if a is greater
+ * than b.
+ */
+int irc_nick_cmp(const char *a, const char *b) {
+    char ac;
+    char bc;
+    char diff;
+    for (;;) {
+        ac = *(a++);
+        bc = *(b++);
+        
+        // Change into IRC uppercase (see RFC 2812 section 2.2)
+        if (ac >= 'a' && ac <= '~') ac &= ~0x20;
+        if (bc >= 'a' && bc <= '~') bc &= ~0x20;
+        
+        diff = ac - bc;
+        if (diff) return diff;
+        if (!ac) return 0;
+    }
+}
+
+
diff --git a/plugins/fishlim/irc.h b/plugins/fishlim/irc.h
new file mode 100644
index 00000000..0c1e7463
--- /dev/null
+++ b/plugins/fishlim/irc.h
@@ -0,0 +1,43 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef IRC_H
+#define IRC_H
+
+#ifdef _MSC_VER
+#include "bool.h"
+#else
+#include <stdbool.h>
+#endif
+#include <stddef.h>
+
+bool irc_parse_message(const char *words[],
+                       const char **prefix, const char **command,
+                       size_t *parameters_offset);
+char *irc_prefix_get_nick(const char *prefix);
+int irc_nick_cmp(const char *a, const char *b);
+
+#endif
+
+
diff --git a/plugins/fishlim/keystore.c b/plugins/fishlim/keystore.c
new file mode 100644
index 00000000..d97107fd
--- /dev/null
+++ b/plugins/fishlim/keystore.c
@@ -0,0 +1,209 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "irc.h"
+#include "fish.h"
+#include "misc.h"
+#include "keystore.h"
+#include "plugin_xchat.h"
+
+
+static char *keystore_password = NULL;
+
+
+/**
+ * Opens the key store file: ~/.xchat2/blow.ini
+ */
+static GKeyFile *getConfigFile() {
+    gchar *filename = get_config_filename();
+    
+    GKeyFile *keyfile = g_key_file_new();
+    g_key_file_load_from_file(keyfile, filename,
+                              G_KEY_FILE_KEEP_COMMENTS |
+                              G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
+    
+    g_free(filename);
+    return keyfile;
+}
+
+
+/**
+ * Returns the key store password, or the default.
+ */
+static const char *get_keystore_password() {
+    return (keystore_password != NULL ?
+        keystore_password :
+        // Silly default value...
+        "blowinikey");
+}
+
+
+/**
+ * Gets a value for a nick/channel from blow.ini. Unlike
+ * g_key_file_get_string, this function is case insensitive.
+ */
+static gchar *get_nick_value(GKeyFile *keyfile, const char *nick, const char *item) {
+    gchar **group;
+    gchar **groups = g_key_file_get_groups(keyfile, NULL);
+    gchar *result = NULL;
+    
+    for (group = groups; *group != NULL; group++) {
+        if (!irc_nick_cmp(*group, nick)) {
+            result = g_key_file_get_string(keyfile, *group, item, NULL);
+            break;
+        }
+    }
+    
+    g_strfreev(groups);
+    return result;
+}
+
+
+/**
+ * Extracts a key from the key store file.
+ */
+char *keystore_get_key(const char *nick) {
+    // Get the key
+    GKeyFile *keyfile = getConfigFile();
+    gchar *value = get_nick_value(keyfile, nick, "key");
+    g_key_file_free(keyfile);
+    if (!value) return NULL;
+    
+    if (strncmp(value, "+OK ", 4) != 0) {
+        // Key is stored in plaintext
+        return import_glib_string(value);
+    } else {
+        // Key is encrypted
+        const char *encrypted = value+4;
+        const char *password = get_keystore_password();
+        char *decrypted = fish_decrypt(password, strlen(password), encrypted);
+        g_free(value);
+        return decrypted;
+    }
+}
+
+/**
+ * Deletes a nick and the associated key in the key store file.
+ */
+static bool delete_nick(GKeyFile *keyfile, const char *nick) {
+    gchar **group;
+    gchar **groups = g_key_file_get_groups(keyfile, NULL);
+    bool ok = false;
+    
+    for (group = groups; *group != NULL; group++) {
+        if (!irc_nick_cmp(*group, nick)) {
+            ok = g_key_file_remove_group(keyfile, *group, NULL);
+            break;
+        }
+    }
+    
+    g_strfreev(groups);
+    return ok;
+}
+
+/**
+ * Writes the key store file to disk.
+ */
+static bool save_keystore(GKeyFile *keyfile) {
+    char *filename;
+    bool ok;
+    // Serialize
+    gsize file_length;
+    gchar *file_data = g_key_file_to_data(keyfile, &file_length, NULL);
+    if (!file_data) return false;
+    
+    // Write to file
+    filename = get_config_filename();
+    ok = g_file_set_contents(filename, file_data, file_length, NULL);
+    g_free(filename);
+    g_free(file_data);
+    return ok;
+}
+
+/**
+ * Sets a key in the key store file.
+ */
+bool keystore_store_key(const char *nick, const char *key) {
+    const char *password;
+    char *encrypted;
+    char *wrapped;
+    bool ok = false;
+    GKeyFile *keyfile = getConfigFile();
+    
+    // Remove old key
+    delete_nick(keyfile, nick);
+    
+    // Add new key
+    password = get_keystore_password();
+    if (password) {
+        // Encrypt the password
+        encrypted = fish_encrypt(password, strlen(password), key);
+        if (!encrypted) goto end;
+        
+        // Prepend "+OK "
+        wrapped = g_strconcat("+OK ", encrypted, NULL);
+        g_free(encrypted);
+        
+        // Store encrypted in file
+        g_key_file_set_string(keyfile, nick, "key", wrapped);
+        free(wrapped);
+    } else {
+        // Store unencrypted in file
+        g_key_file_set_string(keyfile, nick, "key", key);
+    }
+    
+    // Save key store file
+    ok = save_keystore(keyfile);
+    
+  end:
+    g_key_file_free(keyfile);
+    return ok;
+}
+
+/**
+ * Deletes a nick from the key store.
+ */
+bool keystore_delete_nick(const char *nick) {
+    GKeyFile *keyfile = getConfigFile();
+    
+    // Delete entry
+    bool ok = delete_nick(keyfile, nick);
+    
+    // Save
+    if (ok) save_keystore(keyfile);
+    
+    g_key_file_free(keyfile);
+    return ok;
+}
+
+
+void keystore_secure_free(void *ptr, size_t size) {
+    secure_erase(ptr, size);
+    free(ptr);
+}
+
+
diff --git a/plugins/fishlim/keystore.h b/plugins/fishlim/keystore.h
new file mode 100644
index 00000000..b0c1c69c
--- /dev/null
+++ b/plugins/fishlim/keystore.h
@@ -0,0 +1,42 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef KEYSTORE_H
+#define KEYSTORE_H
+
+#ifdef _MSC_VER
+#include "bool.h"
+#else
+#include <stdbool.h>
+#endif
+#include <stddef.h>
+
+char *keystore_get_key(const char *nick);
+bool keystore_store_key(const char *nick, const char *key);
+bool keystore_delete_nick(const char *nick);
+
+void keystore_secure_free(void *ptr, size_t size);
+
+#endif
+
diff --git a/plugins/fishlim/makefile.mak b/plugins/fishlim/makefile.mak
new file mode 100644
index 00000000..4d0be66b
--- /dev/null
+++ b/plugins/fishlim/makefile.mak
@@ -0,0 +1,30 @@
+include "..\..\src\makeinc.mak"

+

+TARGET = xcfishlim.dll

+

+CFLAGS = $(CFLAGS)

+

+FISHLIM_OBJECTS = \

+fish.obj \

+irc.obj \

+keystore.obj \

+misc.obj \

+plugin_xchat.obj

+

+all: $(FISHLIM_OBJECTS) fishlim.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcfishlim.dll /def:fishlim.def $(FISHLIM_OBJECTS)

+

+fishlim.def:

+	echo EXPORTS > fishlim.def

+	echo xchat_plugin_init >> fishlim.def

+	echo xchat_plugin_deinit >> fishlim.def

+	echo xchat_plugin_get_info >> fishlim.def

+

+.c.obj:

+	$(CC) $(CFLAGS) $(GLIB) /I.. /c $<

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/fishlim/misc.c b/plugins/fishlim/misc.c
new file mode 100644
index 00000000..32fe3595
--- /dev/null
+++ b/plugins/fishlim/misc.c
@@ -0,0 +1,54 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "misc.h"
+
+
+void secure_erase(void *ptr, size_t size) {
+    // "volatile" prevents this code from being optimized away
+    volatile char* volptr = ptr;
+    while (size--) *volptr++ = 0;
+}
+
+/**
+ * Re-allocates a string with the native allocator.
+ */
+char *import_glib_string(gchar *gstr) {
+    size_t size;
+    char *native;
+    if (g_mem_is_system_malloc()) return gstr;
+    
+    size = strlen(gstr)+1;
+    native = malloc(size);
+    memcpy(native, gstr, size);
+    
+    secure_erase(gstr, size);
+    g_free(gstr);
+    return native;
+}
+
+
diff --git a/plugins/fishlim/misc.h b/plugins/fishlim/misc.h
new file mode 100644
index 00000000..0adc928c
--- /dev/null
+++ b/plugins/fishlim/misc.h
@@ -0,0 +1,36 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef MISC_H
+#define MISC_H
+
+void secure_erase(void *ptr, size_t size);
+
+#ifdef __G_LIB_H__
+char *import_glib_string(gchar *gstr);
+#endif
+
+#endif
+
+
diff --git a/plugins/fishlim/plugin_xchat.c b/plugins/fishlim/plugin_xchat.c
new file mode 100644
index 00000000..01f5d747
--- /dev/null
+++ b/plugins/fishlim/plugin_xchat.c
@@ -0,0 +1,290 @@
+/*
+
+  Copyright (c) 2010-2011 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+// #pragma GCC visibility push(default)
+#ifdef _MSC_VER
+#include "xchat-plugin.h"
+#else
+#include <xchat/xchat-plugin.h>
+#endif
+#define XCHAT_MAX_WORDS 32
+// #pragma GCC visibility pop
+
+//#define EXPORT __attribute((visibility("default")))
+//#define EXPORT
+
+#include "fish.h"
+#include "keystore.h"
+#include "irc.h"
+
+static const char plugin_name[] = "FiSHLiM";
+static const char plugin_desc[] = "Encryption plugin for the FiSH protocol. Less is More!";
+static const char plugin_version[] = "0.0.15";
+
+static const char usage_setkey[] = "Usage: SETKEY [<nick or #channel>] <password>, sets the key for a channel or nick";
+static const char usage_delkey[] = "Usage: DELKEY <nick or #channel>, deletes the key for a channel or nick";
+
+static xchat_plugin *ph;
+
+
+/**
+ * Returns the path to the key store file.
+ */
+gchar *get_config_filename() {
+    return g_build_filename(xchat_get_info(ph, "xchatdirfs"), "blow.ini", NULL);
+}
+
+/**
+ * Appends data to a string. Returns true if there was sufficient memory.
+ * Frees *s and returns false if an error occurs.
+ */
+static bool append(char **s, size_t *length, const char *data) {
+    size_t datalen = strlen(data);
+    char *extended = realloc(*s, *length + datalen + 1);
+    if (!extended) {
+        free(*s);
+        return false;
+    }
+    memcpy(extended + *length, data, datalen + 1);
+    *s = extended;
+    *length += datalen;
+    return true;
+}
+
+
+/*static int handle_debug(char *word[], char *word_eol[], void *userdata) {
+    xchat_printf(ph, "debug incoming: ");
+    for (size_t i = 1; word[i] != NULL && word[i][0] != '\0'; i++) {
+        xchat_printf(ph, ">%s< ", word[i]);
+    }
+    xchat_printf(ph, "\n");
+    return XCHAT_EAT_NONE;
+}*/
+
+/**
+ * Called when a message is to be sent.
+ */
+static int handle_outgoing(char *word[], char *word_eol[], void *userdata) {
+    const char *own_nick;
+    // Encrypt the message if possible
+    const char *channel = xchat_get_info(ph, "channel");
+    char *encrypted = fish_encrypt_for_nick(channel, word_eol[1]);
+    if (!encrypted) return XCHAT_EAT_NONE;
+    
+    // Display message
+    own_nick = xchat_get_info(ph, "nick");
+    xchat_emit_print(ph, "Your Message", own_nick, word_eol[1], NULL);
+    
+    // Send message
+    xchat_commandf(ph, "PRIVMSG %s :+OK %s", channel, encrypted);
+    
+    free(encrypted);
+    return XCHAT_EAT_XCHAT;
+}
+
+/**
+ * Called when a channel message or private message is received.
+ */
+static int handle_incoming(char *word[], char *word_eol[], void *userdata) {
+    const char *prefix;
+    const char *command;
+    const char *recipient;
+    const char *encrypted;
+    const char *peice;
+    char *sender_nick;
+    char *decrypted;
+    char *message;
+    size_t w;
+    size_t ew;
+    size_t uw;
+    size_t length;
+
+    if (!irc_parse_message((const char **)word, &prefix, &command, &w))
+        return XCHAT_EAT_NONE;
+    
+    // Topic (command 332) has an extra parameter
+    if (!strcmp(command, "332")) w++;
+    
+    // Look for encrypted data
+    for (ew = w+1; ew < XCHAT_MAX_WORDS-1; ew++) {
+        const char *s = (ew == w+1 ? word[ew]+1 : word[ew]);
+        if (strcmp(s, "+OK") == 0) goto has_encrypted_data;
+    }
+    return XCHAT_EAT_NONE;
+  has_encrypted_data: ;
+    // Extract sender nick and recipient nick/channel
+    sender_nick = irc_prefix_get_nick(prefix);
+    recipient = word[w];
+    
+    // Try to decrypt with these (the keys are searched for in the key store)
+    encrypted = word[ew+1];
+    decrypted = fish_decrypt_from_nick(recipient, encrypted);
+    if (!decrypted) decrypted = fish_decrypt_from_nick(sender_nick, encrypted);
+    
+    // Check for error
+    if (!decrypted) goto decrypt_error;
+    
+    // Build unecrypted message
+    message = NULL;
+    length = 0;
+    if (!append(&message, &length, "RECV")) goto decrypt_error;
+    
+    for (uw = 1; uw < XCHAT_MAX_WORDS; uw++) {
+        if (word[uw][0] != '\0' && !append(&message, &length, " ")) goto decrypt_error;
+        
+        if (uw == ew) {
+            // Add the encrypted data
+            peice = decrypted;
+            uw++; // Skip "OK+"
+        } else {
+            // Add unencrypted data (for example, a prefix from a bouncer or bot)
+            peice = (uw == w+1 ? word[uw]+1 : word[uw]);
+        }
+        
+        if (!append(&message, &length, peice)) goto decrypt_error;
+    }
+    free(decrypted);
+    
+    // Simulate unencrypted message
+    //xchat_printf(ph, "simulating: %s\n", message);
+    xchat_command(ph, message);
+    
+    free(message);
+    free(sender_nick);
+    return XCHAT_EAT_XCHAT;
+  
+  decrypt_error:
+    free(decrypted);
+    free(sender_nick);
+    return XCHAT_EAT_NONE;
+}
+
+/**
+ * Command handler for /setkey
+ */
+static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
+    const char *nick;
+    const char *key;
+    
+    // Check syntax
+    if (*word[2] == '\0') {
+        xchat_printf(ph, "%s\n", usage_setkey);
+        return XCHAT_EAT_XCHAT;
+    }
+    
+    if (*word[3] == '\0') {
+        // /setkey password
+        nick = xchat_get_info(ph, "channel");
+        key = word_eol[2];
+    } else {
+        // /setkey #channel password
+        nick = word[2];
+        key = word_eol[3];
+    }
+    
+    // Set password
+    if (keystore_store_key(nick, key)) {
+        xchat_printf(ph, "Stored key for %s\n", nick);
+    } else {
+        xchat_printf(ph, "\00305Failed to store key in blow.ini\n", nick, key);
+    }
+    
+    return XCHAT_EAT_XCHAT;
+}
+
+/**
+ * Command handler for /delkey
+ */
+static int handle_delkey(char *word[], char *word_eol[], void *userdata) {
+    const char *nick;
+    
+    // Check syntax
+    if (*word[2] == '\0' || *word[3] != '\0') {
+        xchat_printf(ph, "%s\n", usage_delkey);
+        return XCHAT_EAT_XCHAT;
+    }
+    
+    nick = word_eol[2];
+    
+    // Delete the given nick from the key store
+    if (keystore_delete_nick(nick)) {
+        xchat_printf(ph, "Deleted key for %s\n", nick);
+    } else {
+        xchat_printf(ph, "\00305Failed to delete key in blow.ini!\n", nick);
+    }
+    
+    return XCHAT_EAT_XCHAT;
+}
+
+/**
+ * Returns the plugin name version information.
+ */
+void xchat_plugin_get_info(const char **name, const char **desc,
+                           const char **version, void **reserved) {
+    *name = plugin_name;
+    *desc = plugin_desc;
+    *version = plugin_version;
+}
+
+/**
+ * Plugin entry point.
+ */
+int xchat_plugin_init(xchat_plugin *plugin_handle,
+                      const char **name,
+                      const char **desc,
+                      const char **version,
+                      char *arg) {
+    ph = plugin_handle;
+    
+    /* Send our info to XChat */
+    *name = plugin_name;
+    *desc = plugin_desc;
+    *version = plugin_version;
+    
+    /* Register commands */
+    xchat_hook_command(ph, "SETKEY", XCHAT_PRI_NORM, handle_setkey, usage_setkey, NULL);
+    xchat_hook_command(ph, "DELKEY", XCHAT_PRI_NORM, handle_delkey, usage_delkey, NULL);
+    
+    /* Add handlers */
+    xchat_hook_command(ph, "", XCHAT_PRI_NORM, handle_outgoing, NULL, NULL);
+    xchat_hook_server(ph, "NOTICE", XCHAT_PRI_NORM, handle_incoming, NULL);
+    xchat_hook_server(ph, "PRIVMSG", XCHAT_PRI_NORM, handle_incoming, NULL);
+    //xchat_hook_server(ph, "RAW LINE", XCHAT_PRI_NORM, handle_debug, NULL);
+    xchat_hook_server(ph, "TOPIC", XCHAT_PRI_NORM, handle_incoming, NULL);
+    xchat_hook_server(ph, "332", XCHAT_PRI_NORM, handle_incoming, NULL);
+    
+    xchat_printf(ph, "%s plugin loaded\n", plugin_name);
+    /* Return success */
+    return 1;
+}
+
+int xchat_plugin_deinit(void) {
+    xchat_printf(ph, "%s plugin unloaded\n", plugin_name);
+    return 1;
+}
+
diff --git a/plugins/fishlim/plugin_xchat.h b/plugins/fishlim/plugin_xchat.h
new file mode 100644
index 00000000..0243e81f
--- /dev/null
+++ b/plugins/fishlim/plugin_xchat.h
@@ -0,0 +1,31 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#ifndef XCHAT_PLUGIN_H
+#define XCHAT_PLUGIN_H
+
+gchar *get_config_filename();
+
+#endif
+
diff --git a/plugins/fishlim/test.c b/plugins/fishlim/test.c
new file mode 100644
index 00000000..3511bbb1
--- /dev/null
+++ b/plugins/fishlim/test.c
@@ -0,0 +1,91 @@
+/*
+
+  Copyright (c) 2010 Samuel Lidén Borell <samuel@slbdata.se>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+*/
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include "fish.h"
+
+// We can't use the XChat plugin API from here...
+gchar *get_config_filename() {
+    const gchar *homedir = g_get_home_dir();
+    return g_build_filename(homedir, ".xchat2", "blow.ini", NULL);
+}
+
+
+static int decrypt(int nick_count, char *nicks[]) {
+    char encrypted[8192];
+    while (fgets(encrypted, sizeof(encrypted), stdin)) {
+        char *msg;
+        for (int i = 0; i < nick_count; i++) {
+            msg = fish_decrypt_from_nick(nicks[i], encrypted);
+            if (msg) goto success;
+        }
+        fprintf(stderr, "None of the recipients were found in the key store!\n");
+        return 1;
+      success:
+        fprintf(stderr, "Decrypted text >>>%s<<<\n", msg);
+    }
+    return 0;
+}
+
+static int encrypt(int nick_count, char *nicks[]) {
+    char message[8192];
+    while (fgets(message, sizeof(message), stdin)) {
+        // Remove newline character
+        char *newline = strchr(message, '\n');
+        if (newline) *newline = '\0';
+        
+        bool error = false;
+        for (int i = 0; i < nick_count; i++) {
+            char *encrypted = fish_encrypt_for_nick(nicks[i], message);
+            if (encrypted) {
+                fprintf(stderr, "Encrypted [%s]:  >>>%s<<<\n", nicks[i], encrypted);
+            } else {
+                error = true;
+            }
+        }
+        
+        if (error) {
+            fprintf(stderr, "Some of the recipients were't found in the key store!\n");
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[]) {
+    if (argc < 2) {
+        fprintf(stderr, "usage: %s [-e] nick...\n", argv[0]);
+        return 2;
+    }
+    
+    if (strcmp(argv[1], "-e") == 0) {
+        return encrypt(argc-2, &argv[2]);
+    } else {
+        return decrypt(argc-1, &argv[1]);
+    }
+}
+
+
diff --git a/plugins/gtkpref/gtkpref.c b/plugins/gtkpref/gtkpref.c
new file mode 100644
index 00000000..5cc754bf
--- /dev/null
+++ b/plugins/gtkpref/gtkpref.c
@@ -0,0 +1,69 @@
+/* XChat-WDK
+ * Copyright (c) 2011 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <windows.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+
+static void
+launch_tool ()
+{
+	STARTUPINFO si;
+	PROCESS_INFORMATION pi;
+
+	ZeroMemory (&si, sizeof (si));
+	si.cb = sizeof (si);
+	ZeroMemory (&pi, sizeof (pi));
+
+	if (!CreateProcess ( NULL, "gtk2-prefs.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+	{
+		xchat_print (ph, "Error launching the GTK+ Preference Tool! Maybe the executable is missing?");
+	}
+
+	CloseHandle (pi.hProcess);
+	CloseHandle (pi.hThread);
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = "GTKPref";
+	*plugin_desc = "GTK+ Preference Tool Launcher";
+	*plugin_version = "1.0";
+
+	xchat_hook_command (ph, "GTKPREF", XCHAT_PRI_NORM, launch_tool, 0, 0);
+	xchat_command (ph, "MENU -ietc\\gtkpref.png ADD \"Settings/GTK+ Preferences\" \"GTKPREF\"");
+
+	return 1;       /* return 1 for success */
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_command (ph, "MENU DEL \"Settings/GTK+ Preferences\"");
+
+	return 1;
+}
diff --git a/plugins/gtkpref/makefile.mak b/plugins/gtkpref/makefile.mak
new file mode 100644
index 00000000..e2292365
--- /dev/null
+++ b/plugins/gtkpref/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: gtkpref.obj gtkpref.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcgtkpref.dll /def:gtkpref.def gtkpref.obj

+

+gtkpref.def:

+	echo EXPORTS > gtkpref.def

+	echo xchat_plugin_init >> gtkpref.def

+	echo xchat_plugin_deinit >> gtkpref.def

+

+gtkpref.obj: gtkpref.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. gtkpref.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/lua/lua.c b/plugins/lua/lua.c
new file mode 100644
index 00000000..9f29bf08
--- /dev/null
+++ b/plugins/lua/lua.c
@@ -0,0 +1,1882 @@
+/* 
+ * X-Chat 2.0 LUA Plugin
+ *
+ * Copyright (c) 2007 Hanno Hecker
+ * 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; version 2 of the License.
+ *
+ * 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: lua.c 91 2007-06-09 18:44:03Z vetinari $
+ *	$Revision: 91 $
+ *	$Date: 2007-06-09 20:44:03 +0200 (Szo, 09 jún. 2007) $
+ */
+/* 
+ * TODO:
+ *   * compile (was OK)/run on IRIX
+ *   ? localize error msgs? ... maybe later
+ *   ? make xchat.print() like print() which does an tostring() on 
+ *     everything it gets?
+ *   ? add /LUA -s <code>? ... add a new script from cmdline... this state
+ *        is not removed after the pcall(), but prints a name, which may
+ *        be used to unload this virtual script. ... no xchat_register(),
+ *        xchat_init() should be needed
+ *        ... don't disable xchat.hook_* for this
+ *   ? timer name per state/script and not per plugin?
+ */
+#define LXC_NAME "Lua"
+#define LXC_DESC "Lua scripting interface"
+#define LXC_VERSION "0.7 (r91)"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifdef _WIN32
+#include <direct.h>	/* for getcwd */
+#include "../../src/common/dirent-win32.h"
+#endif
+
+#if !( defined(_WIN32) || defined(LXC_XCHAT_GETTEXT) )
+#  include <libintl.h>
+#endif
+
+#ifndef PATH_MAX /* hurd */
+# define PATH_MAX 1024 
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define lua_pop(L,n)  lua_settop(L, -(n)-1)
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph; /* plugin handle */
+
+#define LXC_STRIP_COLOR 1
+#define LXC_STRIP_ATTR  2
+#define LXC_STRIP_ALL   (LXC_STRIP_COLOR|LXC_STRIP_ATTR)
+
+/* registered hooks */
+struct lxc_hooks {
+	const char *name;
+	xchat_hook *hook;
+	struct lxc_hooks *next;
+};
+
+/* single linked list of all lua states^Wscripts ;-)  */
+struct lxc_States {
+	lua_State *state;          /* the lua state of the script  */
+	char file[PATH_MAX+1];     /* the file name of the script  */
+	struct lxc_hooks *hooks;   /* all hooks this script registered */
+	void *gui;				/* the gui entry in windows->plugins and scripts... */
+	struct lxc_States *next;
+};
+
+static struct lxc_States *lxc_states = NULL;
+
+/* user/script supplied data for a callback */
+struct lxc_userdata {
+	int idx;					/* table index */
+	int type;				/* lua type:                          */	
+	const char *string;  /* only strings, ...                  */
+	double num;          /* numbers and booleans are supported */
+	struct lxc_userdata *next;	
+};
+
+/* callback data */
+struct lxc_cbdata {
+	lua_State *state;
+	const char *func;
+	xchat_hook *hook; /* timer ... */
+	struct lxc_userdata *data;
+};
+
+static char lxc_event_name[1024] = "\0";
+
+static int lxc_run_hook(char *word[], char *word_eol[], void *data);
+static int lxc_run_print(char *word[], void *data);
+static int lxc_run_timer(void *data);
+
+static int lxc_hook_command(lua_State *L);
+static int lxc_hook_server(lua_State *L);
+static int lxc_hook_print(lua_State *L);
+static int lxc_event(lua_State *L);
+static int lxc_hook_timer(lua_State *L);
+static int lxc_unhook(lua_State *L);
+
+static int lxc_command(lua_State *L);
+static int lxc_print(lua_State *L);
+static int lxc_emit_print(lua_State *L);
+static int lxc_send_modes(lua_State *L);
+static int lxc_find_context(lua_State *L);
+static int lxc_get_context(lua_State *L);
+static int lxc_get_info(lua_State *L);
+static int lxc_get_prefs(lua_State *L);
+static int lxc_set_context(lua_State *L);
+static int lxc_nickcmp(lua_State *L);
+
+static int lxc_list_get(lua_State *L);
+static int lxc_list_fields(lua_State *L);
+static int lxc_gettext(lua_State *L);
+
+static int lxc_bits(lua_State *L);
+
+static luaL_reg lxc_functions[] = {
+	{"hook_command",		lxc_hook_command },
+/* TODO:
+	{"hook_fd",				lxc_hook_fd      },
+*/
+	{"hook_print",			lxc_hook_print   },
+	{"hook_server",		lxc_hook_server  },
+	{"hook_timer",			lxc_hook_timer  },
+	{"unhook",				lxc_unhook  },
+
+	{"event",				lxc_event   },
+
+	{"command",				lxc_command  	  },
+	{"print", 				lxc_print     	  },
+	{"emit_print",			lxc_emit_print },
+	{"send_modes",			lxc_send_modes },
+	{"find_context",		lxc_find_context },
+	{"get_context",		lxc_get_context },
+	{"get_info",			lxc_get_info },
+	{"get_prefs",			lxc_get_prefs },
+	{"set_context",		lxc_set_context },
+
+	{"nickcmp", 			lxc_nickcmp 	},
+
+	{"list_get",			lxc_list_get },
+ 	{"list_fields",		lxc_list_fields }, 
+
+   {"gettext",				lxc_gettext},
+/* helper function for bit flags */
+	{"bits",					lxc_bits },
+	{NULL, NULL}
+};
+
+static struct {
+	const char *name;
+	long value;
+} lxc_consts[] = {
+	{"EAT_NONE", 	XCHAT_EAT_NONE},
+	{"EAT_XCHAT", 	XCHAT_EAT_XCHAT},
+	{"EAT_PLUGIN",	XCHAT_EAT_PLUGIN},
+	{"EAT_ALL",		XCHAT_EAT_ALL},
+
+/* unused until hook_fd is done 
+	{"FD_READ",			XCHAT_FD_READ},
+	{"FD_WRITE",		XCHAT_FD_WRITE},
+	{"FD_EXCEPTION",	XCHAT_FD_EXCEPTION},
+	{"FD_NOTSOCKET",	XCHAT_FD_NOTSOCKET},
+   */
+
+	{"PRI_HIGHEST", 	XCHAT_PRI_HIGHEST},
+	{"PRI_HIGH", 		XCHAT_PRI_HIGH},
+	{"PRI_NORM", 		XCHAT_PRI_NORM},
+	{"PRI_LOW", 		XCHAT_PRI_LOW},
+	{"PRI_LOWEST", 	XCHAT_PRI_LOWEST},
+
+	/* for: clean = xchat.strip(dirty, xchat.STRIP_ALL) */
+	{"STRIP_COLOR",	LXC_STRIP_COLOR},
+	{"STRIP_ATTR",    LXC_STRIP_ATTR},
+	{"STRIP_ALL",     LXC_STRIP_ALL},
+
+   /* for xchat.commandf("GUI COLOR %d", xchat.TAB_HILIGHT) */
+	{"TAB_DEFAULT",  0},
+	{"TAB_NEWDATA",  1},
+	{"TAB_NEWMSG",   2},
+	{"TAB_HILIGHT",  3},
+
+	{NULL,				0}
+};
+
+
+#ifdef DEBUG
+static void stackDump (lua_State *L, const char *msg) {
+	int i, t;
+	int top = lua_gettop(L);
+
+	fprintf(stderr, "%s\n", msg);
+	for (i = 1; i <= top; i++) {  /* repeat for each level */
+	 t = lua_type(L, i);
+	 switch (t) {
+
+		case LUA_TSTRING:  /* strings */
+		  fprintf(stderr, "`%s'", lua_tostring(L, i));
+		  break;
+
+		case LUA_TBOOLEAN:  /* booleans */
+		  fprintf(stderr, lua_toboolean(L, i) ? "true" : "false");
+		  break;
+
+		case LUA_TNUMBER:  /* numbers */
+		  fprintf(stderr, "%g", lua_tonumber(L, i));
+		  break;
+
+		default:  /* other values */
+		  fprintf(stderr, "%s", lua_typename(L, t));
+		  break;
+
+	 }
+	 fprintf(stderr, "  ");  /* put a separator */
+  }
+  fprintf(stderr, "\n");  /* end the listing */
+}
+#endif /* DEBUG */
+
+static int lxc__newindex(lua_State *L)
+{
+	int i;
+	const char *name = lua_tostring(L, 2);
+
+	luaL_getmetatable(L, "xchat"); /* 4 */
+
+	lua_pushnil(L);                /* 5 */
+	while (lua_next(L, 4) != 0) {
+		if ((lua_type(L, -2) == LUA_TSTRING) 
+					&& strcmp("__index", lua_tostring(L, -2)) == 0)
+				break; /* now __index is 5, table 6 */	
+		lua_pop(L, 1);
+	}
+
+	lua_pushnil(L);
+	while (lua_next(L, 6) != 0) {
+		if ((lua_type(L, -2) == LUA_TSTRING)
+				&& strcmp(name, lua_tostring(L, -2)) == 0) {
+			for (i=0; lxc_consts[i].name; i++) {
+				if (strcmp(name, lxc_consts[i].name) == 0) {
+					luaL_error(L, 
+						"`xchat.%s' is a readonly constant", lua_tostring(L, 2));
+					return 0;
+				}
+			}
+		}
+		lua_pop(L, 1);
+	}
+
+	lua_pushvalue(L, 2);
+	lua_pushvalue(L, 3);
+	lua_rawset(L, 6);
+
+	lua_settop(L, 1);
+	return 0;
+}
+
+static int luaopen_xchat(lua_State *L)
+{
+	int i;
+/* 
+ * wrappers for xchat.printf() and xchat.commandf() 
+ * ... xchat.strip 
+ */
+#define LXC_WRAPPERS  "function xchat.printf(...)\n" \
+						 "    xchat.print(string.format(unpack(arg)))\n" \
+						 "end\n" \
+						 "function xchat.commandf(...)\n" \
+						 "    xchat.command(string.format(unpack(arg)))\n" \
+						 "end\n" \
+						 "function xchat.strip(str, flags)\n" \
+						 "    if flags == nil then\n" \
+						 "        flags = xchat.STRIP_ALL\n" \
+						 "    end\n" \
+						 "    local bits = xchat.bits(flags)\n" \
+						 "    if bits[1] then\n" \
+						 "        str = string.gsub(\n" \
+						 "            string.gsub(str, \"\\3%d%d?,%d%d?\", \"\"),\n" \
+						 "                \"\\3%d%d?\", \"\")\n" \
+						 "    end\n" \
+						 "    if bits[2] then\n" \
+						 "        -- bold, beep, reset, reverse, underline\n" \
+						 "        str = string.gsub(str,\n" \
+						 "            \"[\\2\\7\\15\\22\\31]\", \"\")\n" \
+						 "    end\n" \
+						 "    return str\n" \
+						 "end\n"
+
+#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501)
+	luaL_register(L, "xchat", lxc_functions);
+	(void)luaL_dostring(L, LXC_WRAPPERS);
+#else
+	luaL_openlib(L, "xchat", lxc_functions, 0);
+	lua_dostring(L, LXC_WRAPPERS);
+#endif
+	
+	luaL_newmetatable(L, "xchat");
+
+	lua_pushliteral(L, "__index");
+	lua_newtable(L); 
+
+	lua_pushstring(L, "ARCH");
+#ifdef _WIN32
+	lua_pushstring(L, "Windows");
+#else
+	lua_pushstring(L, "Unix");
+#endif
+	lua_settable(L, -3); /* add to table __index */
+
+	for (i=0; lxc_consts[i].name; i++) {
+		lua_pushstring(L, lxc_consts[i].name);
+		lua_pushnumber(L, lxc_consts[i].value);
+		lua_settable(L, -3); /* add to table __index */
+	}
+	lua_settable(L, -3); /* add to metatable */
+
+	lua_pushliteral(L, "__newindex");   
+	lua_pushcfunction(L, lxc__newindex); 
+	lua_settable(L, -3);                
+/* 
+	lua_pushliteral(L, "__metatable");
+	lua_pushstring(L, "nothing to see here, move along");
+	lua_settable(L, -3);               
+*/
+	lua_setmetatable(L, -2);
+	lua_pop(L, 1);
+	return 1;
+}
+
+lua_State *lxc_new_state() 
+{
+#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501)
+	lua_State *L = luaL_newstate();     /* opens Lua */
+	luaL_openlibs(L);
+#else
+	lua_State *L = lua_open();     /* opens Lua */
+	luaopen_base(L);    /* opens the basic library */
+	luaopen_table(L);   /* opens the table library */
+	luaopen_io(L);      /* opens the I/O library */
+	luaopen_string(L);  /* opens the string lib. */
+	luaopen_math(L);    /* opens the math lib. */
+#endif
+
+	luaopen_xchat(L);
+	return L;
+}
+
+static int
+lxc_load_file(const char *script)
+{
+	lua_State *L;
+	struct lxc_States *state;  /* pointer to lua states list */
+	struct lxc_States *st;  /* pointer to lua states list */
+
+	L = lxc_new_state();
+	state = malloc(sizeof(struct lxc_States));
+	if (state == NULL) {
+		xchat_printf(ph, "malloc() failed: %s\n", strerror(errno));
+		lua_close(L);
+		return 0;
+	}
+
+	state->state = L;
+	snprintf(state->file, PATH_MAX, script);
+	state->next  = NULL;
+	state->hooks = NULL;
+	state->gui   = NULL;
+
+	if (luaL_loadfile(L, script) || lua_pcall(L, 0, 0, 0)) {
+		xchat_printf(ph, "Lua plugin: error loading script %s", 	
+							lua_tostring(L, -1));
+		lua_close(L);
+		free(state);
+		return 0;
+	}
+
+	if (!lxc_states) 
+		lxc_states = state;
+	else {
+		st = lxc_states;
+		while (st->next)
+			st = st->next;
+		st->next = state;
+	}
+
+	return 1;
+}
+
+static void
+lxc_autoload_from_path(const char *path)
+{
+	DIR *dir;
+	struct dirent *ent;
+	char *file;
+	int len;
+	/* xchat_printf(ph, "loading from %s\n", path); */
+	dir = opendir(path);
+	if (dir) {
+		while ((ent = readdir(dir))) {
+			len = strlen(ent->d_name);
+			if (len > 4 && strcasecmp(".lua", ent->d_name + len - 4) == 0) {
+				file = malloc(len + strlen(path) + 2);
+				if (file == NULL) {
+					xchat_printf(ph, "lxc_autoload_from_path(): malloc failed: %s",
+						strerror(errno));
+					break;
+				}
+				sprintf(file, "%s/%s", path, ent->d_name);
+				(void)lxc_load_file((const char *)file);
+				free(file);
+			}
+		}
+		closedir(dir);
+	}
+}
+
+void lxc_unload_script(struct lxc_States *state)
+{
+	struct lxc_hooks *hooks, *h;
+	struct lxc_cbdata *cb;
+	struct lxc_userdata *ud, *u;
+	lua_State *L = state->state;
+
+	lua_pushstring(L, "xchat_unload");
+	lua_gettable(L, LUA_GLOBALSINDEX);
+	if (lua_type(L, -1) == LUA_TFUNCTION) {
+		if (lua_pcall(L, 0, 0, 0)) {
+			xchat_printf(ph, "Lua plugin: error while unloading script %s", 	
+								lua_tostring(L, -1));
+			lua_pop(L, 1);
+		}
+	}
+
+	if (state->gui)
+		xchat_plugingui_remove(ph, state->gui);
+	state->gui = NULL;
+
+	hooks = state->hooks;
+	while (hooks) {
+		h     = hooks;
+		hooks = hooks->next;
+
+		cb    = xchat_unhook(ph, h->hook);
+		if (cb) {
+			ud    = cb->data;
+			while (ud) {
+				u  = ud;
+				ud = ud->next;
+				free(u);
+			}
+			free(cb);
+		}
+
+		free(h);
+	}
+	lua_close(state->state);
+}
+
+
+static int lxc_cb_load(char *word[], char *word_eol[], void *userdata)
+{
+	int len;
+	struct lxc_States *state;
+	lua_State *L;
+	const char *name, *desc, *vers;
+	const char *xdir = "";
+	char  *buf;
+	char file[PATH_MAX+1];
+	struct stat *st;
+
+	if (word_eol[2][0] == 0)
+		return XCHAT_EAT_NONE;
+	
+	buf = malloc(PATH_MAX + 1);
+	if (!buf) {
+		xchat_printf(ph, "malloc() failed: %s\n", strerror(errno));
+		return XCHAT_EAT_NONE;
+	}
+
+	st = malloc(sizeof(struct stat));
+	if (!st) {
+		xchat_printf(ph, "malloc() failed: %s\n", strerror(errno));
+		free(buf);
+		return XCHAT_EAT_NONE;
+	}
+
+ 	len = strlen(word[2]);
+	if (len > 4 && strcasecmp (".lua", word[2] + len - 4) == 0) {
+#ifdef WIN32
+		if (strrchr(word[2], '\\') != NULL)
+#else
+		if (strrchr(word[2], '/') != NULL)
+#endif
+			strncpy(file, word[2], PATH_MAX);
+		else {
+			if (stat(word[2], st) == 0)
+				xdir = getcwd(buf, PATH_MAX);
+			else {
+				xdir = xchat_get_info(ph, "xchatdirfs");
+				if (!xdir) /* xchatdirfs is new for 2.0.9, will fail on older */
+					xdir = xchat_get_info (ph, "xchatdir");
+			}
+			snprintf(file, PATH_MAX, "%s/%s", xdir, word[2]);
+		}
+
+		if (lxc_load_file((const char *)file) == 0) {
+			free(st);
+			free(buf);
+			return XCHAT_EAT_ALL;
+		}
+
+		state = lxc_states;
+		while (state) {
+			if (state->next == NULL) {
+				L = state->state;
+
+				lua_pushstring(L, "xchat_register");
+				lua_gettable(L, LUA_GLOBALSINDEX);
+				if (lua_pcall(L, 0, 3, 0)) {
+					xchat_printf(ph, "Lua plugin: error registering script %s", 	
+								lua_tostring(L, -1));
+					lua_pop(L, 1);
+					free(st);
+					free(buf);
+					return XCHAT_EAT_ALL;
+				}
+
+				name = lua_tostring(L, -3);
+				desc = lua_tostring(L, -2);
+				vers = lua_tostring(L, -1);
+				lua_pop(L, 4); /* func + 3 ret value */
+				state->gui = xchat_plugingui_add(ph, state->file, 
+																 name, desc, vers, NULL
+															);
+
+				lua_pushstring(L, "xchat_init");
+				lua_gettable(L, LUA_GLOBALSINDEX);
+				if (lua_type(L, -1) != LUA_TFUNCTION) 
+					lua_pop(L, 1);
+				else {
+					if (lua_pcall(L, 0, 0, 0)) {
+						xchat_printf(ph, 
+									"Lua plugin: error calling xchat_init() %s", 	
+									lua_tostring(L, -1));
+						lua_pop(L, 1);
+					}
+				}
+				free(st);
+				free(buf);
+				return XCHAT_EAT_ALL;
+			}
+			state = state->next;
+		}
+	}
+	free(st);
+	free(buf);
+	return XCHAT_EAT_NONE;
+}
+
+static int lxc_cb_unload(char *word[], char *word_eol[], void *userdata)
+{
+	int len;
+	struct lxc_States *state;
+	struct lxc_States *prev = NULL;
+	char *file;
+
+	if (word_eol[2][0] == 0)
+		return XCHAT_EAT_NONE;
+
+	len = strlen(word[2]);
+	if (len > 4 && strcasecmp(".lua", word[2] + len - 4) == 0) {
+		state = lxc_states;
+		while (state) {
+			/* 
+			 * state->file is the full or relative path, always with a '/' inside,
+			 * even if loaded via '/LOAD script.lua'. So strrchr() will never
+			 * be NULL.
+			 * ... we just inspect the script name w/o path to see if it's the 
+			 * right one to unload
+			 */
+			file = strrchr(state->file, '/') + 1; 
+			if ((strcmp(state->file, word[2]) == 0) 
+					|| (strcasecmp(file, word[2]) == 0)) {
+				lxc_unload_script(state);
+				if (prev) 
+					prev->next = state->next;
+				else
+					lxc_states = state->next;
+				xchat_printf(ph, "Lua script %s unloaded", file);
+				free(state);
+				return XCHAT_EAT_ALL;
+			}
+			prev  = state;
+			state = state->next;
+		}
+	}
+	return XCHAT_EAT_NONE;
+}
+
+static int lxc_cb_lua(char *word[], char *word_eol[], void *userdata)
+{
+	lua_State *L = lxc_new_state();
+	if (word[2][0] == '\0') {
+		xchat_printf(ph, "LUA: Usage: /LUA LUA_CODE... execute LUA_CODE");
+		return XCHAT_EAT_ALL;
+	}
+	if (luaL_loadbuffer(L, word_eol[2], strlen(word_eol[2]), "/LUA")) {
+		xchat_printf(ph, "LUA: error loading line %s", lua_tostring(L, -1));
+		lua_pop(L, 1);
+	}
+
+#define LXC_HOOK_DISABLE "xchat.hook_command = nil\n" \
+								 "xchat.hook_server  = nil\n" \
+								 "xchat.hook_print   = nil\n" \
+								 "xchat.hook_timer   = nil\n"
+
+#if defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM >= 501)
+	(void)luaL_dostring(L, LXC_HOOK_DISABLE);
+#else
+	lua_dostring(L, LXC_HOOK_DISABLE);
+#endif
+
+	if (lua_pcall(L, 0, 0, 0)) {
+		xchat_printf(ph, "LUA: error executing line %s", lua_tostring(L, -1));
+		lua_pop(L, 1);
+	}
+
+	lua_close(L);
+	return XCHAT_EAT_ALL;
+}
+
+int xchat_plugin_init(xchat_plugin *plugin_handle,
+                      char **plugin_name,
+                      char **plugin_desc,
+                      char **plugin_version,
+                      char *arg)
+{
+	struct lxc_States	*state;	
+	lua_State *L;
+	const char *xdir;
+	const char *name, *desc, *vers;
+   /* we need to save this for use with any xchat_* functions */
+   ph = plugin_handle;
+
+   /* tell xchat our info */
+   *plugin_name = LXC_NAME;
+   *plugin_desc = LXC_DESC;
+   *plugin_version = LXC_VERSION;
+
+	xchat_hook_command(ph, "LOAD", XCHAT_PRI_NORM, lxc_cb_load, NULL, NULL);
+	xchat_hook_command(ph, "UNLOAD", XCHAT_PRI_NORM, lxc_cb_unload, NULL, NULL);
+	xchat_hook_command(ph, "LUA", XCHAT_PRI_NORM, lxc_cb_lua, "Usage: LUA <code>, executes <code> in a new lua state", NULL);
+
+	xdir = xchat_get_info(ph, "xchatdirfs");
+	if (!xdir) /* xchatdirfs is new for 2.0.9, will fail on older */
+		xdir = xchat_get_info (ph, "xchatdir");
+		
+	lxc_autoload_from_path(xdir);
+
+	if (!lxc_states) /* no scripts loaded */
+		return 1;
+	
+	state = lxc_states;
+	while (state) {
+		L = state->state;
+		lua_pushstring(L, "xchat_register");
+		lua_gettable(L, LUA_GLOBALSINDEX);
+		if (lua_pcall(L, 0, 3, 0)) {
+			xchat_printf(ph, "Lua plugin: error registering script %s", 	
+								lua_tostring(L, -1));
+			lua_pop(L, 1);
+			state = state->next;
+			continue;
+		}
+
+		name = lua_tostring(L, -3);
+		desc = lua_tostring(L, -2);
+		vers = lua_tostring(L, -1);
+		lua_pop(L, 4); /* func + 3 ret value */
+		state->gui = xchat_plugingui_add(ph, state->file, name, desc, vers, NULL);
+
+		lua_pushstring(L, "xchat_init");
+		lua_gettable(L, LUA_GLOBALSINDEX);
+		if (lua_type(L, -1) != LUA_TFUNCTION) 
+			lua_pop(L, 1);
+		else {
+			if (lua_pcall(L, 0, 0, 0)) {
+				xchat_printf(ph, "Lua plugin: error calling xchat_init() %s", 	
+								lua_tostring(L, -1));
+				lua_pop(L, 1);
+			}
+		}
+		state = state->next;
+	}
+	xchat_printf(ph, "Lua interface (v%s) loaded", LXC_VERSION);
+	return 1; 
+}
+
+int xchat_plugin_deinit(xchat_plugin *plug_handle) 
+{
+	struct lxc_States *state, *st;
+
+	state = lxc_states;
+	while (state) {
+		lxc_unload_script(state);
+		xchat_printf(ph, "Lua script %s unloaded", state->file);
+		st    = state;
+		state = state->next;
+		free(st);
+	}
+	xchat_printf(plug_handle, "Lua plugin v%s removed", LXC_VERSION);
+	return 1;
+}
+
+/*
+ * lua:  func_name(word, word_eol, data)
+ * desc: your previously hooked callback function for hook_command() and
+ *       hook_server(), you must return one of the xchat.EAT_* constants
+ * ret:  none
+ * args: 
+ *       * word (table): the incoming line split into words (max 32)
+ *       * word_eol (table): 
+ *         for both see 
+ *          http://xchat.org/docs/plugin20.html#word
+ *       * data (table): the data table you passed to the hook_command() /
+ *         hook_server() as 5th arg
+ */
+static int lxc_run_hook(char *word[], char *word_eol[], void *data)
+{
+	struct lxc_cbdata *cb   = data;
+	lua_State *L            = cb->state;
+	struct lxc_userdata *ud = cb->data;
+	struct lxc_userdata *u;
+	int i;
+	lua_pushstring(L, cb->func);
+	lua_gettable(L, LUA_GLOBALSINDEX);
+
+	strcpy(lxc_event_name, word[0]);
+	lua_newtable(L);
+	for (i=1; i<=31 && word[i][0]; i++) {
+		lua_pushnumber(L, i);
+		lua_pushstring(L, word[i]);
+		lua_settable(L, -3);
+	}
+
+	lua_newtable(L);
+	for (i=1; i<=31 && word_eol[i][0]; i++) {
+		lua_pushnumber(L, i);
+		lua_pushstring(L, word_eol[i]);
+		lua_settable(L, -3);
+	}
+
+	lua_newtable(L);
+	u = ud;
+	while (u) {
+		lua_pushnumber(L, u->idx);
+		switch (u->type) {
+			case LUA_TSTRING:
+				lua_pushstring(L, u->string);
+				break;
+			case LUA_TNUMBER:
+				lua_pushnumber(L, u->num);
+				break;
+			case LUA_TBOOLEAN:
+				lua_pushboolean(L, (((int)u->num == 0) ? 0 : 1));
+				break;
+			default: /* LUA_TNIL or others */
+				lua_pushnil(L);
+				break;
+		}
+		lua_settable(L, -3);
+		u = u->next;
+	}
+
+	if (lua_pcall(L, 3, 1, 0)) {
+		xchat_printf(ph, "failed to call callback for '%s': %s", 
+				word[1], lua_tostring(L, -1)
+			);
+		lua_pop(L, 1);
+		return XCHAT_EAT_NONE;
+	}
+
+	if (lua_type(L, -1) != LUA_TNUMBER) {
+		xchat_printf(ph, "callback for '%s' did not return number...", word[1]);
+		return XCHAT_EAT_NONE;
+	}
+
+	i = (int)lua_tonumber(L, -1);
+	lua_pop(L, 1);
+	return i;
+}
+
+static int lxc_get_userdata(int pos, struct lxc_cbdata *cb)
+{
+	struct lxc_userdata *ud, *u;
+	lua_State *L = cb->state;
+	int i, t;
+
+	t = lua_type(L, pos);
+	if (t == LUA_TNIL)
+		return 1;
+	if (t != LUA_TTABLE)
+		return 0;
+
+	i = 1;
+	while (1) {
+		lua_pushnumber(L, i);
+		lua_gettable(L, -2);
+
+		t = lua_type(L, -1);
+		if (t == LUA_TNIL) {
+			lua_pop(L, 1);
+			break;
+		}
+
+		ud = malloc(sizeof(struct lxc_userdata));
+		if (!ud) {
+			xchat_printf(ph, "lxc_get_userdata(): failed to malloc: %s", 
+																strerror(errno));
+			if (cb->data != NULL) {
+				ud = cb->data;
+				while (ud) {
+					u  = ud;
+					ud = ud->next;
+					free(u);
+				}
+			}
+			/* free(cb); NO! */
+			lua_pushnil(L);
+			return 0;
+		}
+		ud->idx = i;
+		ud->next = NULL;
+		switch (t) {
+			case LUA_TSTRING:
+				ud->string = lua_tostring(L, -1);
+				ud->type   = LUA_TSTRING;
+				break;
+			case LUA_TNUMBER:
+				ud->num    = lua_tonumber(L, -1);
+				ud->type   = LUA_TNUMBER;
+				break;
+			case LUA_TBOOLEAN:
+				ud->num    = (double)lua_toboolean(L, -1);
+				ud->type   = LUA_TBOOLEAN;
+				break;
+			default:
+				ud->type   = LUA_TNIL;
+				break;
+		}
+		lua_pop(L, 1);
+
+		if (cb->data == NULL)
+			cb->data = ud;
+		else {
+			u = cb->data;
+			while (u->next)
+				u = u->next;
+			u->next = ud;
+		}
+		i++;
+	} /* END while (1) */
+	return 1;
+}
+
+/* 
+ * lua:  xchat.hook_command(name, func_name, prio, help_str, data)
+ * desc: Adds a new /command. This allows your program to handle commands 
+ *       entered at the input box. To capture text without a "/" at the start 
+ *       (non-commands), you may hook a special name of "". i.e 
+ *           xchat.hook_command( "", ...)
+ * 		Starting from version 2.6.8, commands hooked that begin with a 
+ * 		period ('.') will be hidden in /HELP and /HELP -l. 
+ * ret:  true... or false if something went wrong while registering hook
+ * args: 
+ *       * name (string): the name of the new command
+ *       * func_name (string): the lua function to be called when command is
+ *          entered
+ *       * prio (number): use one of the xchat.PRIO_*
+ *       * help_str (string): help for the new command... use nil for no help
+ *       * data (table): table with strings, numbers and booleans, which will
+ *         be passed to func_name as last argument.
+ */
+static int lxc_hook_command(lua_State *L)
+{
+	xchat_hook *hook;
+	const char *help, *command, *func;
+	double prio;
+	struct lxc_hooks *hooks, *h;
+	struct lxc_States *st;
+	struct lxc_cbdata *cb;
+
+
+	if (lua_gettop(L) < 5) /* expand to five args if necessary */
+		lua_settop(L, 5);
+
+	cb = malloc(sizeof(struct lxc_cbdata));
+	if (!cb) {
+		xchat_printf(ph, "lxc_hook_command(): failed to malloc: %s", 
+																	strerror(errno));
+		lua_pushboolean(L, 0);
+		return 1;
+	}
+
+	cb->state = L;
+	cb->data = NULL;
+
+	command 	= luaL_checkstring(L, 1);
+	func     = luaL_checkstring(L, 2);
+	cb->func = func;
+	cb->hook = NULL;
+
+	if (lua_type(L, 3) == LUA_TNIL)
+		prio = XCHAT_PRI_NORM;
+	else
+		prio = luaL_checknumber(L, 3);
+
+	if (lua_type(L, 4) == LUA_TSTRING) {
+		help = luaL_checkstring(L, 4);
+		if (strlen(help) == 0)
+			help = NULL;
+	}
+	else
+		help = NULL;
+	
+	if (lxc_get_userdata(5, cb) == 0) 
+		lua_pushboolean(L, 0);
+	else {
+		h = malloc(sizeof(struct lxc_hooks));
+		if (!h) {
+			xchat_printf(ph, "lxc_hook_command(): failed to malloc: %s", 
+																	strerror(errno));
+			lua_pushboolean(L, 0);
+			return 1;
+		}
+		hook    = xchat_hook_command(ph, command, prio, lxc_run_hook, help, cb);
+		h->hook = hook;
+		h->name = command;
+		h->next = NULL;
+		st      = lxc_states;
+		while (st) {
+			if (st->state == L) {
+				if (!st->hooks) 
+					st->hooks = h;
+				else {
+					hooks     = st->hooks;
+					while (hooks->next) 
+						hooks = hooks->next;
+					hooks->next = h;
+				}
+				break;
+			}
+			st = st->next;
+		}
+		lua_pushboolean(L, 1);
+	}
+	return 1;
+}
+
+/*
+ * lua:  func_name(word, data)
+ * desc: your previously hooked callback function for hook_print(), 
+ *       you must return one of the xchat.EAT_* constants
+ * ret:  none
+ * args: 
+ *       * word (table): the incoming line split into words (max 32)
+ *         (see http://xchat.org/docs/plugin20.html#word)
+ *       * data (table): the data table you passed to the hook_print() /
+ *         as 4th arg
+ */
+static int lxc_run_print(char *word[], void *data)
+{
+	struct lxc_cbdata *cb = data;
+	lua_State *L          = cb->state;
+	int i;
+
+	lua_pushstring(L, cb->func);
+	lua_gettable(L, LUA_GLOBALSINDEX);
+
+	strcpy(lxc_event_name, word[0]);
+	lua_newtable(L);
+	for (i=1; i<=31 && word[i][0]; i++) {
+		lua_pushnumber(L, i);
+		lua_pushstring(L, word[i]);
+		lua_settable(L, -3);
+	}
+
+	if (lua_pcall(L, 1, 1, 0)) {
+		xchat_printf(ph, "failed to call callback for '%s': %s", 
+			word[1], lua_tostring(L, -1));
+		lua_pop(L, 1);
+		return 0;
+	}
+
+	if (lua_type(L, -1) != LUA_TNUMBER) {
+		xchat_printf(ph, "callback for '%s' didn't return number...", word[1]);
+		return XCHAT_EAT_NONE;
+	}
+	i = (int)lua_tonumber(L, -1);
+	lua_pop(L, 1);
+	return i;
+}
+
+/* 
+ * lua:  xchat.hook_print(name, func_name, prio, data)
+ * desc: Registers a function to trap any print events. The event names may 
+ *       be any available in the "Advanced > Text Events" window. There are 
+ *       also some extra "special" events you may hook using this function,
+ *       see: http://xchat.org/docs/plugin20.html#xchat_hook_print
+ * ret:  true... or false if something went wrong while registering hook
+ * args: 
+ *       * name (string): the name of the new command
+ *       * prio (number): use one of the xchat.PRIO_*
+ *       * func_name (string): the lua function to be called when command is
+ *         entered
+ *       * data (table): table with strings, numbers and booleans, which will
+ *         be passed to func_name as last argument.
+ */
+static int lxc_hook_print(lua_State *L)
+{
+	xchat_hook *hook;
+	struct lxc_hooks *hooks, *h;
+	struct lxc_States *st;
+	struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata));
+	const char *name, *func;
+	double prio;
+
+	if (!cb) {
+		luaL_error(L, "lxc_hook_print(): failed to malloc: %s", strerror(errno));
+		return 0;
+	}
+
+	if (lua_gettop(L) < 4) /* expand to 4 args if necessary */
+		lua_settop(L, 4);
+
+	name = luaL_checkstring(L, 1);
+	func = luaL_checkstring(L, 2);
+	if (lua_type(L, 3) == LUA_TNIL)
+		prio = XCHAT_PRI_NORM;
+	else
+		prio = luaL_checknumber(L, 3);
+
+	cb->state = L;
+	cb->func  = func;
+	cb->data  = NULL;
+	cb->hook  = NULL;
+
+	if (lxc_get_userdata(4, cb) == 0) 
+		lua_pushboolean(L, 0);
+	else {
+		h = malloc(sizeof(struct lxc_hooks));
+		if (!h) {
+			xchat_printf(ph, "lxc_hook_print(): failed to malloc: %s", 
+																	strerror(errno));
+			lua_pushboolean(L, 0);
+			return 1;
+		}
+		hook 	  = xchat_hook_print(ph, name, prio, lxc_run_print, cb); 
+		h->hook = hook;
+		h->name = name;
+		h->next = NULL;
+		st      = lxc_states;
+		while (st) {
+			if (st->state == L) {
+				if (!st->hooks)
+					st->hooks = h;
+				else {
+					hooks     = st->hooks;
+					while (hooks->next) 
+						hooks = hooks->next;
+					hooks->next = h;
+				}
+				break;
+			}
+			st = st->next;
+		}
+		lua_pushboolean(L, 1);
+	}
+	return 1;
+}
+
+/*
+ * lua:  xchat.hook_server(name, func_name, prio, data)
+ * desc: Registers a function to be called when a certain server event 
+ *       occurs. You can use this to trap PRIVMSG, NOTICE, PART, a server 
+ *       numeric etc... If you want to hook every line that comes from the 
+ *       IRC server, you may use the special name of "RAW LINE".
+ * ret:  true... or false if something went wrong while registering
+ * args: 
+ *       * name (string): the event name / numeric (yes, also as a string)
+ *       * prio (number): one of the xchat.PRIO_* constants
+ *       * func_name (string): the function to be called, when the event
+ *           happens
+ *       * data (table)... see xchat.hook_command()
+ */
+static int lxc_hook_server(lua_State *L)
+{
+	xchat_hook *hook;
+	struct lxc_hooks *hooks, *h;
+	struct lxc_States *st;
+	const char *name, *func;
+	double prio;
+
+	struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata));
+	if (!cb) {
+		xchat_printf(ph, "lxc_hook_server(): failed to malloc: %s", 
+																	 strerror(errno));
+		lua_pushnil(L);
+		return 1;
+	}
+
+	if (lua_gettop(L) < 4) /* expand to 4 args if necessary */
+		lua_settop(L, 4);
+
+	name = luaL_checkstring(L, 1);
+	func = luaL_checkstring(L, 2);
+	if (lua_type(L, 3) == LUA_TNIL)
+		prio = XCHAT_PRI_NORM;
+	else
+		prio = luaL_checknumber(L, 3);
+
+	cb->state = L;
+	cb->func = func;
+	cb->data = NULL;
+	cb->hook = NULL;
+
+	if (lxc_get_userdata(4, cb) == 0) 
+		lua_pushboolean(L, 0);
+	else {
+		h = malloc(sizeof(struct lxc_hooks));
+		if (!h) {
+			xchat_printf(ph, "lxc_hook_server(): failed to malloc: %s", 
+																	strerror(errno));
+			lua_pushboolean(L, 0);
+			return 1;
+		}
+		hook    = xchat_hook_server(ph, name, prio, lxc_run_hook, cb); 
+		h->hook = hook;
+		h->name = name;
+		h->next = NULL;
+		st      = lxc_states;
+		while (st) {
+			if (st->state == L) {
+				if (!st->hooks)
+					st->hooks = h;
+				else {
+					hooks     = st->hooks;
+					while (hooks->next) 
+						hooks = hooks->next;
+					hooks->next = h;
+				}
+				break;
+			}
+			st = st->next;
+		}
+		lua_pushboolean(L, 1);
+	}
+	return 1;
+}
+
+/* 
+ * lua:  xchat.hook_timer(timeout, func_name, data)
+ * desc: Registers a function to be called every "timeout" milliseconds.
+ * ret:  true (or false on error while registering)
+ * args: 
+ *       * timeout (number): Timeout in milliseconds (1000 is 1 second). 
+ *       * func_name (string): Callback function. This will be called 
+ *           every "timeout" milliseconds. 
+ *       * data (table): see xchat.hook_command()
+ */
+
+static unsigned long long lxc_timer_count = 0;
+
+static int lxc_hook_timer(lua_State *L)
+{
+	xchat_hook *hook;
+	struct lxc_hooks *hooks, *h;
+	struct lxc_States *st;
+	double timeout;
+	const char *func;
+	char name[32];
+
+	struct lxc_cbdata *cb = malloc(sizeof(struct lxc_cbdata));
+	if (!cb) {
+		luaL_error(L, "lxc_hook_timer(): failed to malloc: %s", strerror(errno));
+		lua_pushnil(L);
+		return 1;
+	}
+
+	if (lua_gettop(L) < 3) /* expand to 3 args if necessary */
+		lua_settop(L, 3);
+
+	timeout = luaL_checknumber(L, 1);
+	func    = luaL_checkstring(L, 2);
+
+	cb->state = L;
+	cb->func  = func;
+	cb->data  = NULL;
+
+	if (lxc_get_userdata(3, cb) == 0) 
+		lua_pushnil(L);
+	else {
+		h = malloc(sizeof(struct lxc_hooks));
+		if (!h) {
+			luaL_error(L, "lxc_hook_timer(): failed to malloc: %s", 
+				strerror(errno));
+			return 0;
+		}
+		hook 	   = xchat_hook_timer(ph, timeout, lxc_run_timer, cb); 
+		cb->hook = hook;
+		h->hook  = hook;
+		h->next  = NULL;
+		snprintf(name, 31, "timer%llu", lxc_timer_count++);
+		h->name  = name;
+		lua_pushstring(L, name);
+
+		st       = lxc_states;
+		while (st) {
+			if (st->state == L) {
+				if (!st->hooks)
+					st->hooks = h;
+				else {
+					hooks     = st->hooks;
+					while (hooks->next)
+						hooks = hooks->next;
+					hooks->next = h;
+				}
+				break;
+			}
+			st = st->next;
+		}
+	}
+	return 1;
+}
+
+static void lxc_unhook_timer(lua_State *L, xchat_hook *hook)
+{
+	struct lxc_States *state;
+	struct lxc_hooks *hooks, *h, *prev_hook;
+	struct lxc_cbdata *cb;
+	struct lxc_userdata *ud, *u;
+
+	prev_hook = NULL;
+	state = lxc_states;
+	while (state) {
+		if (state->state == L) {
+			hooks = state->hooks;
+			while (hooks) {
+				if (hooks->hook == hook) {
+					h  = hooks;
+					if (prev_hook)
+						prev_hook->next = hooks->next;
+					else
+						state->hooks = hooks->next;
+
+					cb = xchat_unhook(ph, h->hook);
+					if (cb) {
+						 ud = cb->data;
+						 while (ud) {
+							 u  = ud;
+							 ud = ud->next;
+							 free(u);
+						 }
+						 free(cb);
+					}
+
+					free(h);
+					return;
+				}
+				prev_hook = hooks;
+				hooks = hooks->next;
+			}
+			break;
+		}
+		state = state->next;
+	}
+}
+
+/* 
+ * lua:  func_name(data)
+ * desc: the callback function for the registered timer hook, return
+ *       true to keep this timer going, false to stop it
+ * ret:  none
+ * args: 
+ *       * data (table): the table you gave the hook_timer() as last
+ *           argument
+ */
+ static int lxc_run_timer(void *data)
+{
+	int ret;
+	struct lxc_cbdata *cb = data;
+	xchat_hook *hook      = cb->hook;
+	lua_State *L          = cb->state;
+
+	lua_pushstring(L, cb->func);
+	lua_gettable(L, LUA_GLOBALSINDEX);
+
+	if (lua_pcall(L, 0, 1, 0)) {
+		xchat_printf(ph, "failed to call timer callback for '%s': %s", 
+			cb->func, lua_tostring(L, -1));
+		lua_pop(L, 1);
+		lxc_unhook_timer(L, hook);
+		return 0;
+	}
+
+	if (lua_type(L, -1) != LUA_TBOOLEAN) {
+		xchat_printf(ph, 
+			"timer callback for '%s' didn't return a boolean", cb->func);
+		lua_pop(L, 1);
+		lxc_unhook_timer(L, hook);
+		return 0;
+	}
+
+	ret = (lua_toboolean(L, -1) == 0) ? 0 : 1;
+	lua_pop(L, 1);
+
+	if (ret == 0)
+		lxc_unhook_timer(L, hook);
+
+	return ret;
+}
+
+/*
+ * lua:  xchat.unhook(name)
+ * desc: unhooks a previously hooked hook 
+ * ret:  true if the hook existed, else false..
+ * args: 
+ *       * name (string): name of a registered hook (e.g. with 
+ *         xchat.hook_command("whois", ... ) you would unhook "whois"
+ *         ... see timer warnings... there's currently just one "timer"
+ *         to unhook
+ */
+static int lxc_unhook(lua_State *L)
+{
+	struct lxc_States *state;
+	struct lxc_hooks *hooks, *h, *prev_hook;
+	struct lxc_cbdata *cb;
+	struct lxc_userdata *ud, *u;
+	int done = 0;
+	const char *name = luaL_checkstring(L, 1);
+
+	prev_hook = NULL;
+	state = lxc_states;
+	while (state) {
+		if (state->state == L) {
+			hooks = state->hooks;
+			while (hooks) {
+				if (strcasecmp(hooks->name, name) == 0) {
+					h  = hooks;
+					if (prev_hook)
+						prev_hook->next = hooks->next;
+					else
+						state->hooks = hooks->next;
+
+					cb = xchat_unhook(ph, h->hook);
+					if (cb) {
+						ud = cb->data;
+						while (ud) {
+							u  = ud;
+							ud = ud->next;
+							free(u);
+						}
+						free(cb);
+					}
+
+					free(h);
+					done = 1;
+					break;
+				}
+				prev_hook = hooks;
+				hooks = hooks->next;
+			}
+			break;
+		}
+		state = state->next;
+	}
+	lua_pushboolean(L, done);
+	return 1;
+}
+
+static int lxc_event(lua_State *L)
+{
+	lua_pushstring(L, lxc_event_name);
+	return 1;
+}
+
+/* 
+ * lua:  xchat.command(command) 
+ * desc: executes a command as if it were typed in xchat's input box. 
+ * ret:  none
+ * args: 
+ *       * command (string): command to execute, without the forward slash "/". 
+ */
+static int lxc_command(lua_State *L)
+{
+	const char *command = luaL_checkstring(L, 1);
+	xchat_command(ph, command);
+	return 0;
+}
+
+/* 
+ * lua:  xchat.print(text)
+ * desc: Prints some text to the current tab/window.
+ * ret:  none
+ * args: 
+ *       * text (string): the text to print
+ */
+static int lxc_print(lua_State *L)
+{
+	const char *txt = luaL_checkstring(L, 1);
+	// FIXME? const char *txt = lua_tostring(L, 1);
+	xchat_print(ph, txt);
+	return 0;
+}
+
+/*
+ * lua: xchat.emit_print(event, text, [text2, ...])
+ * desc: Generates a print event. This can be any event found in the 
+ *       Preferences > Advanced > Text Events window. The vararg parameter 
+ *       list MUST be no longer than four (4) parameters. 
+ *       Special care should be taken when calling this function inside a 
+ *       print callback (from xchat.hook_print()), as not to cause endless 
+ *       recursion. 
+ * ret:  true on success, false on error
+ * args: 
+ *       * event (string): the event name from the references > Advanced > 
+ *         Text Events window
+ *       * text (string)
+ *         text2 (string)
+ *         ... (string(s)):
+ *           parameters for the given event
+ */
+static int lxc_emit_print(lua_State *L)
+{
+
+	int n = lua_gettop(L);
+	const char *text[5];
+	const char *event;
+	int i = 2;
+
+	if (n > 6)
+		luaL_error(L, "too many arguments to xchat.emit_print()");
+
+	event = luaL_checkstring(L, 1);
+	while (i <= n) {
+		text[i-2] = luaL_checkstring(L, i);
+		i++;
+	}
+	switch (n-1) {
+		case 0:
+			i = xchat_emit_print(ph, event, NULL);
+			break;
+		case 1:
+			i = xchat_emit_print(ph, event, text[0], NULL);
+			break;
+		case 2:
+			i = xchat_emit_print(ph, event, text[0], text[1], NULL);
+			break;
+		case 3:
+			i = xchat_emit_print(ph, event, text[0], text[1], text[2], NULL);
+			break;
+		case 4:
+			i = xchat_emit_print(ph, event, text[0], text[1], text[2], text[3], NULL);
+			break;
+	}
+	lua_pushboolean(L, (i == 0) ? 0 : 1);
+	return 1;
+}
+
+/* 
+ * lua:  xchat.send_modes(targets, sign, mode [, modes_per_line])
+ * desc: Sends a number of channel mode changes to the current channel. 
+ *       For example, you can Op a whole group of people in one go. It may 
+ *       send multiple MODE lines if the request doesn't fit on one. Pass 0 
+ *       for modes_per_line to use the current server's maximum possible. 
+ *       This function should only be called while in a channel context. 
+ * ret:  none
+ * args: 
+ *       * targets (table): list of names
+ *       * sign (string): mode sign, i.e. "+" or "-", only the first char of
+ *            this is used (currently unchecked if it's really "+" or "-")
+ *       * mode (string): mode char, i.e. "o" for opping, only the first 
+ *            char of this is used (currently unchecked, what char)
+ *       * modes_per_line (number): [optional] number of modes per line
+ */
+static int lxc_send_modes(lua_State *L)
+{
+	int i = 1;
+	const char *name, *mode, *sign;
+	const char *targets[4096];
+	int num = 0; /* modes per line */
+
+	if (!lua_istable(L, 1)) {
+		luaL_error(L, 
+			"xchat.send_modes(): first argument is not a table: %s", 
+			lua_typename(L, lua_type(L, 1)));
+		return 0;
+	}
+
+	while (1) {
+		lua_pushnumber(L, i); /* push index on stack */
+		lua_gettable(L, 1);   /* and get the element @ index */
+		if (lua_isnil(L, -1)) { /* end of table */
+			lua_pop(L, 1);
+			break;
+		}
+
+		if (lua_type(L, -1) != LUA_TSTRING) { /* oops, something wrong */
+			luaL_error(L, 
+				"lua: xchat.send_modes(): table element #%d not a string: %s",
+				i, lua_typename(L, lua_type(L, -1)));
+			lua_pop(L, 1);
+			return 0;
+		}
+
+		name = lua_tostring(L, -1);
+		if (name == NULL) { /* this should not happen, but... */
+			lua_pop(L, 1);
+			break;
+		}
+
+		targets[i-1] = name;
+		lua_pop(L, 1); /* take index from stack */
+		++i;
+	}
+
+	sign = luaL_checkstring(L, 2);
+	if (sign[0] == '\0' || sign[1] != '\0') {
+		luaL_error(L, "argument #2 (mode sign) does not have length 1");
+		return 0;
+	}
+	if ((sign[0] != '+') && (sign[0] != '-')) {
+		luaL_error(L, "argument #2 (mode sign) is not '+' or '-'");
+		return 0;
+	}
+
+	mode = luaL_checkstring(L, 3);
+	if (mode[0] == '\0' || mode[1] != '\0') {
+		luaL_error(L, "argument #3 (mode char) does not have length 1");
+		return 0;
+	}
+	if (!isalpha((int)mode[0]) || !isascii((int)mode[0])) {
+		luaL_error(L, "argument #3 is not a valid mode character");
+		return 0;
+	}
+
+	if (lua_gettop(L) == 4)
+		num = luaL_checknumber(L, 4);
+	
+	xchat_send_modes(ph, targets, i-1, num, sign[0], mode[0]);
+	return 0;
+}
+
+/*
+ * lua:  xchat.find_context(srv, chan)
+ * desc: Finds a context based on a channel and servername. If servname is nil,
+ *       it finds any channel (or query) by the given name. If channel is nil, 
+ *       it finds the front-most tab/window of the given servname. If nil is 
+ *       given for both arguments, the currently focused tab/window will be 
+ *       returned.
+ *       Changed in 2.6.1. If servname is nil, it finds the channel (or query)
+ *       by the given name in the same server group as the current context. 
+ *       If that doesn't exists then find any by the given name. 
+ * ret:  context number (DON'T modify)
+ * args: 
+ *       * srv (string or nil): server name
+ *       * chan (string or nil): channel / query name
+ */
+static int lxc_find_context(lua_State *L)
+{
+	const char *srv, *chan;
+	long ctx;
+	xchat_context *ptr;
+
+	if (lua_type(L, 1) == LUA_TSTRING) {
+		srv = lua_tostring(L, 1);
+		if (srv[0] == '\0')
+			srv = NULL;
+	}
+	else
+		srv = NULL;
+	
+	if (lua_type(L, 2) == LUA_TSTRING) {
+		chan = lua_tostring(L, 2);
+		if (chan[0] == '\0')
+			chan = NULL;
+	}
+	else
+		chan = NULL;
+	
+	ptr = xchat_find_context(ph, srv, chan);
+	ctx = (long)ptr;
+#ifdef DEBUG
+	fprintf(stderr, "find_context(): %#lx\n", (long)ptr);
+#endif
+	lua_pushnumber(L, (double)ctx);
+	return 1;
+}
+
+/* 
+ * lua:  xchat.get_context()
+ * desc: Returns the current context for your plugin. You can use this later 
+ *       with xchat_set_context. 
+ * ret:  context number ... DON'T modifiy
+ * args: none
+ */
+static int lxc_get_context(lua_State *L)
+{
+	long ptr;
+	xchat_context *ctx = xchat_get_context(ph);
+	ptr = (long)ctx;
+#ifdef DEBUG
+	fprintf(stderr, "get_context(): %#lx\n", ptr);
+#endif
+	lua_pushnumber(L, (double)ptr);
+	return 1;
+}
+
+/* 
+ * lua:  xchat.get_info(id)
+ * desc: Returns information based on your current context.
+ * ret:  the requested string or nil on error
+ * args: 
+ *       * id (string): the wanted information
+ */
+static int lxc_get_info(lua_State *L)
+{
+	const char *id    = luaL_checkstring(L, 1);
+	const char *value = xchat_get_info(ph, id);
+	if (value == NULL)
+		lua_pushnil(L);
+	else
+		lua_pushstring(L, value);
+	return 1;
+}
+
+/*
+ * lua:  xchat.get_prefs(name)
+ * desc: Provides xchat's setting information (that which is available 
+ *       through the /set command). A few extra bits of information are 
+ *       available that don't appear in the /set list, currently they are:
+ *       * state_cursor: Current input-box cursor position (characters, 
+ *                       not bytes). Since 2.4.2.
+ *       *id:            Unique server id. Since 2.6.1.
+ * ret:  returns the string/number/boolean for the given config var
+ *       or nil on error
+ * args:
+ *       * name (string): the wanted setting's name
+ */
+static int lxc_get_prefs(lua_State *L)
+{
+	int i;
+	const char *str;
+	const char *name = luaL_checkstring(L, 1);
+	/* 
+	 * luckily we can store anything in a lua var... this makes the 
+	 * xchat lua api more user friendly ;-) 
+	 */
+	switch (xchat_get_prefs(ph, name, &str, &i)) { 
+		case 0: /* request failed */
+			lua_pushnil(L);
+			break;
+		case 1: 
+			lua_pushstring(L, str);
+			break;
+		case 2:
+			lua_pushnumber(L, (double)i);
+			break;
+		case 3:
+			lua_pushboolean(L, i);
+			break;
+		default: /* doesn't happen if xchat's C-API doesn't change ;-) */
+			lua_pushnil(L);
+			break;
+	}
+	return 1;
+}
+
+/*
+ * lua:  xchat.set_context(ctx)
+ * desc: Changes your current context to the one given. 
+ * ret:  true or false 
+ * args: 
+ *       * ctx (number): the context (e.g. from xchat.get_context())
+ */
+static int lxc_set_context(lua_State *L)
+{
+	double ctx = luaL_checknumber(L, 1);
+#ifdef DEBUG
+	fprintf(stderr, "set_context(): %#lx\n", (long)ctx);
+#endif
+	xchat_context *xc = (void *)(long)ctx;
+	lua_pushboolean(L, xchat_set_context(ph, xc));
+	return 1;
+}
+
+/*
+ * lua:  xchat.nickcmp(name1, name2)
+ * desc: Performs a nick name comparision, based on the current server 
+ *       connection. This might be a RFC1459 compliant string compare, or 
+ *       plain ascii (in the case of DALNet). Use this to compare channels 
+ *       and nicknames. The function works the same way as strcasecmp. 
+ * ret:  number ess than, equal to, or greater than zero if name1 is found, 
+ *       respectively, to be less than, to match, or be greater than name2. 
+ * args:
+ *       * name1 (string): nick or channel name
+ *       * name2 (string): nick or channel name
+ */
+static int lxc_nickcmp(lua_State *L)
+{
+	const char *n1 = luaL_checkstring(L, 1);
+	const char *n2 = luaL_checkstring(L, 2);
+	lua_pushnumber(L, (double)xchat_nickcmp(ph, n1, n2));
+	return 1;
+}
+
+/* 
+ * lua:  xchat.list_get(name)
+ * desc: http://xchat.org/docs/plugin20.html#lists :)
+ *       time_t values are stored as number => e.g.
+ *         os.date("%Y-%m-%d, %H:%M:%S", time_t_value)
+ *       pointers (channel -> context) as number... untested if this works
+ * ret:  table with tables with all keys=Name, value=(Type)... or nil on error
+ * args: 
+ *       * name (string): the wanted list
+ */
+static int lxc_list_get(lua_State *L)
+{
+	const char *name          = luaL_checkstring(L, 1); 
+	int i; /* item index */
+	int l; /* list index */
+	const char *str;
+	double      num;
+	time_t     date;
+	long        ptr;
+	const char *const *fields = xchat_list_fields(ph, name);
+	xchat_list *list          = xchat_list_get(ph, name);
+
+	if (!list) {
+		lua_pushnil(L);
+		return 1;
+	}
+	lua_newtable(L);
+	/* this is like the perl plugin does it ;-) */
+	l = 1;
+	while (xchat_list_next(ph, list)) {
+		i = 0;
+		lua_pushnumber(L, l);
+		lua_newtable(L);
+		while (fields[i] != NULL) {
+			switch (fields[i][0]) {
+				case 's':
+					str = xchat_list_str(ph, list, fields [i] + 1);
+					lua_pushstring(L, fields[i]+1);
+					if (str != NULL)
+						lua_pushstring(L, str);
+					else 
+						lua_pushnil(L);
+					lua_settable(L, -3);
+					break;
+				case 'p':
+					ptr = (long)xchat_list_str(ph, list, fields [i] + 1);
+					num = (double)ptr;
+					lua_pushstring(L, fields[i]+1);
+					lua_pushnumber(L, num);
+					lua_settable(L, -3);
+					break;
+				case 'i':
+					num = (double)xchat_list_int(ph, list, fields[i] + 1);
+					lua_pushstring(L, fields[i]+1);
+					lua_pushnumber(L, num);
+					lua_settable(L, -3);
+					break;
+				case 't':
+					date = xchat_list_time(ph, list, fields[i] + 1);
+					lua_pushstring(L, fields[i]+1);
+					lua_pushnumber(L, (double)date);
+					lua_settable(L, -3);
+					break;
+			}
+			i++;
+		}
+		lua_settable(L, -3);
+		l++;
+	}
+	xchat_list_free(ph, list);
+	return 1;
+}
+
+/*
+ * lua:  xchat.list_fields(name)
+ * desc: returns the possible keys for name as table
+ * ret:  table ;->
+ * args: 
+ *       * name (string): name of the wanted list ("channels", "dcc", 
+ *            "ignore", "notify", "users")
+ */
+static int lxc_list_fields(lua_State *L)
+{
+	const char *name = luaL_checkstring(L, 1);
+	const char *const *fields = xchat_list_fields(ph, name);
+	int i;
+
+	lua_newtable(L);
+	i = 0;
+	while (fields[i] != NULL) {
+		 lua_pushnumber(L, i);
+		 /* first char is the type ... */
+		 lua_pushstring(L, fields[i]+1);
+		 lua_settable(L, -3);
+	}
+	return 1;
+}
+
+/*
+ * lua:  xchat.gettext(str)
+ * desc: 
+ */
+static int lxc_gettext(lua_State *L)
+{
+#if defined(_WIN32) || defined(LXC_XCHAT_GETTEXT)
+	lua_pushstring(L, xchat_gettext(ph, luaL_checkstring(L, 1)));
+#else
+	const char *dom;
+	const char *msgid = luaL_checkstring(L, 1);
+	if (lua_type(L,2) == LUA_TSTRING)
+			dom = lua_tostring(L, 2);
+	else
+			dom = "xchat";
+	lua_pushstring(L, dgettext(dom, msgid));
+#endif
+	return 1;
+}
+
+/*
+ * lua:  xchat.bits(flags)
+ * desc: returns a table of booleans if the bit at index (err... index-1) is
+ *       set
+ * ret:  table of booleans
+ * args: 
+ *       * flags (number)
+  */
+static int lxc_bits(lua_State *L)
+{
+	int flags = luaL_checknumber(L, 1);
+	int i;
+	lua_pop(L, 1);
+	lua_newtable(L);
+	for (i=0; i<16; i++) { /* at time of writing, the highest index was 9 ... */
+		lua_pushnumber(L, i+1);
+		lua_pushboolean(L, ((1<<i) & flags) == 0 ? 0 : 1);
+		lua_settable(L, -3);
+	}
+	return 1;
+}
+/* 
+ * vim: ts=3 noexpandtab
+ */
diff --git a/plugins/lua/makefile.mak b/plugins/lua/makefile.mak
new file mode 100644
index 00000000..97a7e10b
--- /dev/null
+++ b/plugins/lua/makefile.mak
@@ -0,0 +1,20 @@
+include "..\..\src\makeinc.mak"

+

+DIRENTLIB = ..\..\src\common\dirent-win32.lib

+

+all: lua.obj lua.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xclua.dll $(LUALIB).lib $(DIRENTLIB) /def:lua.def lua.obj 

+

+lua.def:

+	echo EXPORTS > lua.def

+	echo xchat_plugin_init >> lua.def

+	echo xchat_plugin_deinit >> lua.def

+

+lua.obj: lua.c makefile.mak

+	cl $(CFLAGS) /I.. /Dsnprintf=g_snprintf lua.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/makefile.mak b/plugins/makefile.mak
new file mode 100644
index 00000000..19b3cb75
--- /dev/null
+++ b/plugins/makefile.mak
@@ -0,0 +1,71 @@
+all:
+	@cd checksum
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\gtkpref
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\dns
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\doat
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\exec
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\fishlim
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\lua
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\mpcinfo
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+#	@cd ..\nonbmp
+#	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\python
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\tcl
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\upd
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\xsasl
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\xtray
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\winamp
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\winsys
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+	@cd ..\wmpa
+	@-$(MAKE) /nologo /s /f makefile.mak $@
+
+clean:
+	@cd checksum
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\gtkpref
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\dns
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\doat
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\exec
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\fishlim
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\lua
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\mpcinfo
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+#	@cd ..\nonbmp
+#	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\python
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\tcl
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\upd
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\xsasl
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\xtray
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\winamp
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\winsys
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
+	@cd ..\wmpa
+	@-$(MAKE) /nologo /s /f makefile.mak clean $@
diff --git a/plugins/mpcinfo/functions.c b/plugins/mpcinfo/functions.c
new file mode 100644
index 00000000..ed0632d4
--- /dev/null
+++ b/plugins/mpcinfo/functions.c
@@ -0,0 +1,167 @@
+/*
+ *  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.
+ */
+
+/*
+typedef int (*MYPROC)(HWND,HWND,char*,char*,BOOL,BOOL); 
+
+int dllProc(char *name, char *data){
+    HINSTANCE hinstLib; 
+    hinstLib = LoadLibrary("mpcinfo");
+    //MYPROC proc;
+    int res;
+    if (hinstLib != NULL){
+       //proc = ;
+       if ((MYPROC) GetProcAddress(hinstLib, name)!=NULL){
+          res=(MYPROC)(NULL,NULL,data,NULL,TRUE,TRUE);
+       }
+       else{fprintf(stderr,"can't get proc: %s\n",name);res=-2;}
+    }
+    else{fprintf(stderr,"can't access dll\n");return -1;}
+    FreeLibrary(hinstLib);
+    return res;
+}
+*/
+
+/*
+int dllProc(char *name, char *data)
+{
+	static HMODULE lib = NULL;
+	if (!lib)
+	{
+		lib = LoadLibraryA ("mpcinfo");
+		if (!lib)
+		{
+			return FALSE;
+		}
+		FreeLibrary (lib);
+	}
+
+	return TRUE;
+}
+*/
+
+char *split(char *text, char seperator){
+     //if (DEBUG==1) putlog("splitting");
+     int i;int pos=-1;
+     for (i=0;i<strlen(text);i++){
+         if (text[i]==seperator){pos=i;i=strlen(text)+1;}
+     }
+     if (pos==-1) return text;
+     text[pos]=0;
+     return &(text[pos+1]);
+}
+
+int endsWith(char *text, char *suffix){
+    char *tmp=strstr(text,suffix);
+    if (tmp==NULL) return 0;
+    if (strlen(tmp)==strlen(suffix)) return 1;
+    return 0;
+}
+
+int inStr(char *s1, int sl1, char *s2){
+    //if (DEBUG==1) putlog("checking instr");
+	int i;int j;
+	for(i=0;i<sl1-strlen(s2);i++){
+		for (j=0;j<strlen(s2);j++){
+			if (s1[i+j]!=s2[j]) j=strlen(s2)+2;
+		}
+		if (j==strlen(s2)) return i;
+	}
+	return -1;
+}
+
+static char *subString(char *text, int first, int length, int spcKill){
+//if (DEBUG==1) putlog("creating substring");
+	char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1));
+	int i;
+	ret[length]=0;
+	for (i=0;i<length;i++){
+		ret[i]=text[i+first];
+		//if (ret[i]==0) ret[i]='0';
+	}
+	if (spcKill==1){
+	   for (i=length-1;i>=0;i--){
+           if (ret[i]==32) ret[i]=0;
+           else i=-1;
+       }
+    }
+    //if (DEBUG==1) putlog("substring created");
+	return ret;
+}
+
+static char *substring(char *text, int first, int length){return subString(text,first,length,0);}
+
+
+char *readLine(FILE *f){
+     //if (DEBUG==1) putlog("reading line from file");
+     char *buffer=(char*)calloc(1024,sizeof(char)); //malloc(sizeof(char)*1024);
+     int pos=0;
+     int cc=0;
+     while((cc!=EOF)&&(pos<1024)&&(cc!=10)){
+          cc=fgetc(f);
+          if ((cc!=10)&&(cc!=13)){
+             if (cc==EOF) buffer[pos]=0;
+             else buffer[pos]=(char)cc;pos++;
+          }
+     }
+     if (buffer[pos]==EOF) xchat_printf(ph,"EOF: %i\n",pos);
+     return buffer;
+}
+
+char *toUpper(char *text){
+     //if (DEBUG==1) putlog("converting text to upper case");
+     char *ret=(char*) calloc(strlen(text)+1,sizeof(char));
+     int i;
+     for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]);
+     ret[strlen(text)]=0;
+     //if (DEBUG==1) putlog("uc done");
+     return ret;
+}
+
+static char *str3cat(char *s1, char *s2, char *s3){
+       //if (DEBUG==1) putlog("cating 3 strings");
+       char *ret=(char*)calloc(strlen(s1)+strlen(s2)+strlen(s3)+1,sizeof(char));
+       strcpy(ret,s1);strcat(ret,s2);strcat(ret,s3);
+       ret[strlen(s1)+strlen(s2)+strlen(s3)]=0;
+       //if (DEBUG==1) putlog("strings cated");
+       return ret;
+}
+
+char *replace(char *text, char *from, char *to){
+     //if (DEBUG==1) putlog("replacing");
+     char *ret=(char*)calloc( strlen(text)+(strlen(to)-strlen(from)),sizeof(char));
+     char *left;
+     char *right;
+     int pos=inStr(text,strlen(text),from);
+     if (pos!=-1){
+           left=substring(text,0,pos);
+           right=substring(text,pos+strlen(from),strlen(text)-(pos+strlen(from)));          
+           ret=str3cat(left,to,right);
+           return replace(ret,from,to);
+     }
+     //if (DEBUG==1) putlog("replaced");
+     return text;
+}
+
+char *intReplaceF(char *text, char *from, int to, char *form){
+     //if (DEBUG==1) putlog("replaceF");
+     char *buffer=(char*) calloc(16,sizeof(char));
+     sprintf(buffer,form,to);
+     //if (DEBUG==1) putlog("replaceF done");
+     return replace(text,from,buffer);
+}
+
+char *intReplace(char *text, char *from, int to){return intReplaceF(text,from,to,"%i");}
diff --git a/plugins/mpcinfo/makefile.mak b/plugins/mpcinfo/makefile.mak
new file mode 100644
index 00000000..4a8a2763
--- /dev/null
+++ b/plugins/mpcinfo/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: mpcinfo.obj mpcinfo.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcmpcinfo.dll /def:mpcinfo.def mpcinfo.obj

+

+mpcinfo.def:

+	echo EXPORTS > mpcinfo.def

+	echo xchat_plugin_init >> mpcinfo.def

+	echo xchat_plugin_deinit >> mpcinfo.def

+

+mpcinfo.obj: mpcinfo.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. mpcinfo.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/mpcinfo/mp3Info.c b/plugins/mpcinfo/mp3Info.c
new file mode 100644
index 00000000..f75ba9c4
--- /dev/null
+++ b/plugins/mpcinfo/mp3Info.c
@@ -0,0 +1,361 @@
+/*
+ *  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.
+ */
+
+//#include <stdio.h>
+#include <sys/stat.h>
+//#include "functions.c"
+
+struct tagInfo{
+	int mode;
+	int cbr;
+	int bitrate;
+	unsigned int freq;
+	char *artist;
+	char *title;
+	char *album;
+	char *comment;
+	char *genre;
+	//int genre;
+	//int track;
+};
+
+static int RATES[2][3][15]={
+				{//mpeg2
+                    {-1,8,16,24,32,64,80,56,64,128,160,112,128,256,320},//layer3 (V2)    
+					{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V2)
+					{-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V2)
+                },
+                {//mpeg1
+					{-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320},//layer3 (V1)
+					{-1,32,48,56,64,80,96,112,128,160,192,224,256,320,384},//layer2 (V1)
+                    {-1,32,64,96,128,160,192,224,256,288,320,352,384,416,448},//layer1 (V1)
+        }};
+static int FREQS[2][4]={{22050,24000,16000,-1},{44100,48000,32000,-1}};
+//static double FRATES[]={38.5,32.5,27.8,0.0};
+
+static char GENRES[][50]={"Blues","Classic Rock","Country","Dance","Disco","Funk","Grunge","Hip-Hop","Jazz","Metal",
+"New Age","Oldies","Other","Pop","R&B","Rap","Reggae","Rock","Techno","Industrial",
+"Alternative","Ska","Death Metal","Pranks","Soundtrack","Euro-Techno","Ambient","Trip-Hop","Vocal","Jazz+Funk",
+"Fusion","Trance","Classical","Instrumental","Acid","House","Game","Sound Clip","Gospel","Noise",
+"AlternRock","Bass","Soul","Punk","Space","Meditative","Instrumental Pop","Instrumental Rock","Ethnic","Gothic",
+"Darkwave","Techno-Industrial","Electronic","Pop-Folk","Eurodance","Dream","Southern Rock","Comedy","Cult","Gangsta",
+"Top 40","Christian Rap","Pop/Funk","Jungle","Native American","Cabaret","New Wave","Psychadelic","Rave","Showtunes",
+"Trailer","Lo-Fi","Tribal","Acid Punk","Acid Jazz","Polka","Retro","Musical","Rock & Roll","Hard Rock",
+
+//################## END OF OFFICIAL ID3 TAGS, WINAMP TAGS BELOW ########################################
+
+"Folk","Folk/Rock","National Folk","Swing","Fast Fusion","Bebob","Latin","Revival","Celtic","Bluegrass",
+"Avantgarde","Gothic Rock","Progressive Rock","Psychedelic Rock","Symphonic Rock","Slow Rock","Big Band","Chorus","Easy Listening","Acoustic",
+"Humour","Speech","Chanson","Opera","Chamber Music","Sonata","Symphony","Booty Bass","Primus","Porn Groove",
+"Satire","Slow Jam","Club","Tango","Samba","Folklore","Ballad","Poweer Ballad","Rhytmic Soul","Freestyle",
+"Duet","Punk Rock","Drum Solo","A Capela","Euro-House","Dance Hall",
+
+//################## FOUND AT http://en.wikipedia.org/wiki/ID3 ###########################################
+
+"Goa","Drum & Bass","Club-House","Hardcore",
+"Terror","Indie","BritPop","Negerpunk","Polsk Punk","Beat","Christian Gangsta Rap","Heavy Metal","Black Metal","Crossover",
+"Contemporary Christian","Christian Rock","Merengue","Salsa","Thrash Metal","Anime","JPop","Synthpop"
+
+};
+
+static char MODES [][13]={"Stereo","Joint-Stereo","Dual-Channel","Mono"};
+
+int iPow(int x, int y){return (int)(pow((double)x,(double) y));}
+
+int str2int(char *text){
+    //if (DEBUG==1) putlog("converting string to int");
+    int i;
+    int ret=0;
+    for (i=1;i<=strlen(text);i++){
+        if ((text[strlen(text)-i]>57)||(text[strlen(text)-i]<48)){
+           xchat_printf(ph,"invalid char in string: %i",text[strlen(text)-i]);
+           return 255;
+        }
+        ret+=((int)text[strlen(text)-i]-48)*iPow(10,i-1);
+    }
+    //xchat_printf(ph, "str2int(%s)=%i",text,ret);
+    //if (DEBUG==1) putlog("int converted");
+    return ret;
+}
+/*
+static int getSize(char *file){
+    //if (DEBUG==1) putlog("reading filesize");
+	struct stat info;
+	if (stat(file,&info)!=0) return -1;
+	return info.st_size;
+}*/
+/*
+int inStr(char *s1, int sl1, char *s2){
+    //if (DEBUG==1) putlog("checking instr");
+	int i;int j;
+	for(i=0;i<sl1-strlen(s2);i++){
+		for (j=0;j<strlen(s2);j++){
+			if (s1[i+j]!=s2[j]) j=strlen(s2)+2;
+		}
+		if (j==strlen(s2)) return i;
+	}
+	return -1;
+}
+
+static char *subString(char *text, int first, int length, int spcKill){
+//if (DEBUG==1) putlog("creating substring");
+	char *ret=(char*) calloc (length+1,sizeof(char)); //malloc(sizeof(char)*(length+1));
+	ret[length]=0;int i;
+	for (i=0;i<length;i++){
+		ret[i]=text[i+first];
+		//if (ret[i]==0) ret[i]='0';
+	}
+	if (spcKill==1){
+	   for (i=length-1;i>=0;i--){
+           if (ret[i]==32) ret[i]=0;
+           else i=-1;
+       }
+    }
+    //if (DEBUG==1) putlog("substring created");
+	return ret;
+}
+
+static char *substring(char *text, int first, int length){return subString(text,first,length,0);} //1
+*/
+
+static char *tagExtract(char *tag, int tagLen, char* info){
+//if (DEBUG==1) putlog("extracting tag");
+	int pos, len, i;
+	pos=inStr(tag,tagLen,info);
+//xchat_printf(ph,"pos=%i",pos);
+	if (pos==-1) return "";//NULL;
+	//printf("position of %s = %i\n",info,pos);
+	len=0;
+	//for (i=pos;i<pos+10;i++)printf("tag[%i]=%i \n",i,tag[i]);
+	for (i=0;i<4;i++) {
+		len+=tag[pos+strlen(info)+i]*iPow(255,3-i);
+	}
+	//printf("Tag-Length: %i\n",len);
+	if (strcmp("COMM",info)!=0) return substring(tag,pos+7+strlen(info),len-1);//11
+	return substring(tag,pos+7+strlen(info),len-1);//11
+	//char *ct=substring(tag,pos+7+strlen(info),len-1);//11
+	//return substring(ct,strlen(ct)+1,len-1-strlen(ct)); //<-- do not understand, what i did here :(
+	
+}
+
+struct tagInfo readID3V1(char *file){
+//if (DEBUG==1) putlog("reading ID3V1");
+	FILE *f;
+	struct tagInfo ret;
+	int res, i, c, val;
+	char *tag;
+	char *id;
+	char *tmp;
+	tag = (char*) malloc(sizeof(char)*129);
+	ret.artist=NULL;
+	f=fopen(file,"rb");
+	if (f==NULL){
+       xchat_print(ph,"file not found while trying to read id3v1");
+       //if (DEBUG==1) putlog("file not found while trying to read id3v1");
+       return ret;
+    }
+	//int offset=getSize(file)-128;
+	res=fseek(f,-128,SEEK_END);
+	if (res!=0) {printf("seek failed\n");fclose(f);return ret;}
+	//long int pos=ftell(f);
+	//printf("position= %li\n",pos);
+	for (i=0;i<128;i++) {
+		c=fgetc(f);
+		if (c==EOF) {xchat_printf(ph,"read ID3V1 failed\n");fclose(f);return ret;}
+		tag[i]=(char)c;
+	}
+	fclose(f);
+	//printf("tag readed: \n");
+	id=substring(tag,0,3);
+	//printf("header: %s\n",id);
+	if (strcmp(id,"TAG")!=0){xchat_printf(ph,"no id3 v1 found\n");return ret;}
+	ret.title=subString(tag,3,30,1);
+	ret.artist=subString(tag,33,30,1);
+	ret.album=subString(tag,63,30,1);
+	ret.comment=subString(tag,97,30,1);
+	tmp=substring(tag,127,1);
+	//ret.genre=substring(tag,127,1);
+	
+	val=(int)tmp[0];
+	if (val<0)val+=256;
+	//xchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]);
+	if ((val<148)&&(val>=0)) 
+       ret.genre=GENRES[val];//#############changed
+	else {
+         ret.genre="unknown";
+         //xchat_printf(ph, "tmp[0]=%i (%i)",val,tmp[0]);
+    }
+	//xchat_printf(ph, "tmp: \"%s\" -> %i",tmp,tmp[0]);
+	//xchat_printf(ph,"genre \"%s\"",ret.genre);
+	//if (DEBUG==1) putlog("id3v1 extracted");
+	return ret;
+}
+
+char *extractID3Genre(char *tag){
+     //if (DEBUG==1) putlog("extracting id3 genre");
+     if (tag[strlen(tag)-1]==')'){
+        tag[strlen(tag)-1]=0;
+        tag=&tag[1];
+        return GENRES[str2int(tag)];
+        //return tag;
+     }
+     else{
+          int i;
+          //xchat_print(ph, "Using 2 criteria");
+          for (i=0;i<strlen(tag);i++){
+              if (tag[i]==')'){ tag=&tag[i]+1;return tag;}
+          //return tag;
+          }
+     }
+     return "[152] failed";
+}
+
+struct tagInfo readID3V2(char *file){
+//if (DEBUG==1) putlog("reading id3v2");
+	FILE *f;
+	int i, c, len;
+	char header[10];
+	char *tag;
+	struct tagInfo ret;
+
+	f = fopen(file,"rb");
+	//xchat_printf(ph,"file :%s",file);
+	if (f==NULL)
+	{
+       xchat_print(ph,"file not found whilt trying to read ID3V2");
+       //if (DEBUG==1)putlog("file not found while trying to read ID3V2");
+       return ret;
+    }
+
+	ret.artist=NULL;
+	for (i=0;i<10;i++){
+        c=fgetc(f);
+        if (c==EOF){
+           //putlog("found eof while reading id3v2");
+           return ret;
+        }
+        header[i]=(char)c;
+    }
+	if (strstr(header,"ID3")==header){
+		//xchat_printf(ph,"found id3v2\n");
+		len=0;
+		for (i=6;i<10;i++) len+=(int)header[i]*iPow(256,9-i);
+		
+		//char *tag=(char*)malloc(sizeof(char)*len);
+		tag=(char*) calloc(len,sizeof(char)); //malloc(sizeof(char)*len);
+		for (i=0;i<len;i++){c=fgetc(f);tag[i]=(char)c;}
+//xchat_printf(ph,"tag length: %i\n",len);
+//xchat_printf(ph,"tag: %s\n",tag);
+		fclose(f);
+		ret.comment=tagExtract(tag,len,"COMM");
+//xchat_printf(ph,"Comment: %s\n",ret.comment);
+		ret.genre=tagExtract(tag,len,"TCON");
+		//if (strcmp(ret.genre,"(127)")==0) ret.genre="unknown";
+//xchat_printf(ph, "ret.genre = %s",ret.genre);
+		if ((ret.genre!=NULL)&&(ret.genre[0]=='(')) ret.genre=extractID3Genre(ret.genre);
+//xchat_printf(ph,"genre: %s\n",ret.genre);
+		ret.title=tagExtract(tag,len,"TIT2");
+//xchat_printf(ph,"Title: %s\n",ret.title);
+		ret.album=tagExtract(tag,len,"TALB");
+//xchat_printf(ph,"Album: %s\n",ret.album);
+		ret.artist=tagExtract(tag,len,"TPE1");
+//xchat_printf(ph,"Artist: %s\n",ret.artist);
+	}
+	else{fclose(f);printf("no id3v2 tag found\n"); return ret;}
+	//printf("id2v2 done\n");
+	//if (DEBUG==1) putlog("id3v2 readed");
+	return ret;
+}
+
+struct tagInfo readHeader(char *file){
+//if (DEBUG==1) putlog("reading header");
+	FILE *f;
+	//int buffer[5120];
+	int versionB, layerB, bitrateB, freqB, modeB;
+	int header[4];
+	int count=0;
+	int cc=0;
+	struct tagInfo info;
+	info.artist=NULL;
+
+	f = fopen(file,"rb");
+	if (f==NULL)
+	{
+       xchat_print(ph,"file not found while trying to read mp3 header");
+       //if (DEBUG==1) putlog("file not found while trying to read mp3 header");
+       return info;
+    }
+	//struct tagInfo tagv2
+	
+	info=readID3V2(file);
+	//struct tagInfo tagv1;//=readID3V1(file);
+	//if 	(tagv2.artist!=NULL){info=tagv2;}
+	//else {
+	if (info.artist==NULL){
+		//printf("searching for id3v1\n");
+		//tagv1=readID3V1(file);
+		info=readID3V1(file); //#####################
+	}
+	/*
+	if (tagv1.artist!=NULL){
+		//printf("Artist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",tagv1.artist,tagv1.title,tagv1.album,tagv1.comment,tagv1.genre);
+		info=tagv1;
+	}
+	*/
+	while ((count<5120)&&(cc!=EOF)&&(cc!=255)) {cc=fgetc(f);count++;}
+	if ((cc==EOF)||(count==5119)) printf("no header found\n");
+	else {
+		//printf("located header at %i\n",count);
+		header[0]=255;
+		for (count=1;count<4;count++){
+			header[count]=fgetc(f);
+			//printf("header[%i]=%i\n",count,header[count]);
+		}
+		versionB=(header[1]&8)>>3;
+		layerB=(header[1]&6)>>1;
+		bitrateB=(header[2]&240)>>4; //4
+		freqB=(header[2]&12)>>2;//2
+		modeB=(header[3]&192)>>6;//6
+		//printf("Mpeg: %i\nLayer: %i\nBitrate: %i\nFreq: %i\nMode: %i\n",versionB, layerB, bitrateB, freqB, modeB);
+		//int Bitrate=RATES[versionB][layerB-1][bitrateB];
+		//int Freq=FREQS[versionB][freqB];
+		info.bitrate=RATES[versionB][layerB-1][bitrateB];
+		info.freq=FREQS[versionB][freqB];
+		info.mode=modeB;	
+	}
+	fclose(f);
+	//if (DEBUG==1) putlog("header readed");
+	return info;
+}
+/*
+static void printMp3Info(char *file){
+	//printf("\nScanning Mp3-File for Informations: %s\n",file);
+	//printf("size:\t%10d byte\n",getSize(file));
+	struct tagInfo info =readHeader(file);
+	printf("%s | %10d",file,getSize(file));
+	if  (info.bitrate>0){
+		//printf("Bitrate: %i\nFreq: %i\nMode: %s\n",info.bitrate,info.freq,MODES[info.mode]);
+		printf(" | %i kbps | %i kHz | %s",info.bitrate,info.freq,MODES[info.mode]);
+		//if (info.artist!=NULL) printf("\nArtist: %s\nTitle: %s\nAlbum: %s\nComment: %s\nGenre: %s\n",info.artist,info.title,info.album,info.comment,info.genre);
+		if (info.artist!=NULL) {
+			printf("| %s | %s | %s | %s | %s",info.artist,info.title,info.album,info.comment,info.genre);
+			//printf("| %s ",info.title);//,info.title,info.album,info.comment,info.genre
+		}
+	}
+	printf("\n");
+	
+}
+*/
diff --git a/plugins/mpcinfo/mpcInfo.c b/plugins/mpcinfo/mpcInfo.c
new file mode 100644
index 00000000..e467e516
--- /dev/null
+++ b/plugins/mpcinfo/mpcInfo.c
@@ -0,0 +1,149 @@
+/*
+ *  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.
+ */
+
+//static int DEBUG=0;
+static char *VERSION="0.0.6";
+
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include "xchat-plugin.h"
+static xchat_plugin *ph;
+
+#include "functions.c"
+#include "mp3Info.c"
+#include "oggInfo.c"
+#include "theme.c"
+
+static int print_themes (char *word[], char *word_eol[], void *userdata){
+       printThemes();
+       return XCHAT_EAT_ALL;
+}
+
+static int mpc_themeReload(char *word[], char *word_eol[], void *userdata){
+   themeInit();
+   loadThemes();
+   return XCHAT_EAT_ALL;
+}
+
+static int mpc_tell(char *word[], char *word_eol[], void *userdata){
+       char *tTitle, *zero, *oggLine, *line;
+	   struct tagInfo info;
+	   HWND hwnd = FindWindow("MediaPlayerClassicW",NULL);
+       if (hwnd==0) {xchat_command(ph, randomLine(notRunTheme));return XCHAT_EAT_ALL;}
+       
+       tTitle=(char*)malloc(sizeof(char)*1024);
+       GetWindowText(hwnd, tTitle, 1024);
+       zero=strstr(tTitle," - Media Player Classic");
+       if (zero!=NULL) zero[0]=0;
+       else xchat_print(ph,"pattern not found");
+       
+       if ((tTitle[1]==':')&&(tTitle[2]=='\\')){
+          //xchat_print(ph,"seams to be full path");
+          if (endsWith(tTitle,".mp3")==1){
+             //xchat_print(ph,"seams to be a mp3 file");
+             info = readHeader(tTitle);
+             
+             if ((info.artist!=NULL)&&(strcmp(info.artist,"")!=0)){
+                char *mode=MODES[info.mode];
+                //xchat_printf(ph,"mode: %s\n",mode);
+                char *mp3Line=randomLine(mp3Theme);
+                mp3Line=replace(mp3Line,"%art",info.artist);
+                mp3Line=replace(mp3Line,"%tit",info.title);
+                mp3Line=replace(mp3Line,"%alb",info.album);
+                mp3Line=replace(mp3Line,"%com",info.comment);
+                mp3Line=replace(mp3Line,"%gen",info.genre);
+                //mp3Line=replace(mp3Line,"%time",pos);
+                //mp3Line=replace(mp3Line,"%length",len);
+                //mp3Line=replace(mp3Line,"%ver",waVers);
+                //mp3Line=intReplace(mp3Line,"%br",br);
+                //mp3Line=intReplace(mp3Line,"%frq",frq);
+                
+                mp3Line=intReplace(mp3Line,"%br",info.bitrate);
+                mp3Line=intReplace(mp3Line,"%frq",info.freq);
+                mp3Line=replace(mp3Line,"%mode",mode);
+                //mp3Line=replace(mp3Line,"%size",size);
+                //mp3Line=intReplace(mp3Line,"%perc",perc);
+                //mp3Line=replace(mp3Line,"%plTitle",title);
+                mp3Line=replace(mp3Line,"%file",tTitle);
+                xchat_command(ph, mp3Line);
+                return XCHAT_EAT_ALL;
+             }
+          }
+          if (endsWith(tTitle,".ogg")==1){
+             xchat_printf(ph,"Ogg detected\n");
+             info = getOggHeader(tTitle);
+             if (info.artist!=NULL){
+                char *cbr;
+                if (info.cbr==1) cbr="CBR"; else cbr="VBR";
+                oggLine=randomLine(oggTheme);
+                //if (cue==1) oggLine=cueLine;
+                //xchat_printf(ph,"ogg-line: %s\n",oggLine);
+                oggLine=replace(oggLine,"%art",info.artist);
+                oggLine=replace(oggLine,"%tit",info.title);
+                oggLine=replace(oggLine,"%alb",info.album);
+                oggLine=replace(oggLine,"%com",info.comment);
+                oggLine=replace(oggLine,"%gen",info.genre);
+                //oggLine=replace(oggLine,"%time",pos);
+                //oggLine=replace(oggLine,"%length",len);
+                //oggLine=replace(oggLine,"%ver",waVers);
+                oggLine=intReplace(oggLine,"%chan",info.mode);
+                oggLine=replace(oggLine,"%cbr",cbr);
+                oggLine=intReplace(oggLine,"%br",info.bitrate/1000);//br);
+                oggLine=intReplace(oggLine,"%frq",info.freq);
+                //oggLine=replace(oggLine,"%size",size);
+                //oggLine=intReplace(oggLine,"%perc",perc);
+                //oggLine=replace(oggLine,"%plTitle",title);
+                oggLine=replace(oggLine,"%file",tTitle);
+                xchat_command(ph, oggLine);
+                return XCHAT_EAT_ALL;
+             }
+          }
+       }
+       line=randomLine(titleTheme);
+       line=replace(line,"%title", tTitle);
+       xchat_command(ph,line); 
+       return XCHAT_EAT_ALL;
+}
+
+int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg){
+	ph = plugin_handle;
+	*plugin_name = "mpcInfo";
+	*plugin_desc = "Information-Script for Media Player Classic"; 
+	*plugin_version=VERSION;
+
+	xchat_hook_command(ph, "mpc", XCHAT_PRI_NORM, mpc_tell,"no help text", 0);
+	xchat_hook_command(ph, "mpc_themes", XCHAT_PRI_NORM, print_themes,"no help text", 0);
+	xchat_hook_command(ph, "mpc_reloadthemes", XCHAT_PRI_NORM, mpc_themeReload,"no help text", 0);
+	xchat_command (ph, "MENU -ietc\\music.png ADD \"Window/Display Current Song (MPC)\" \"MPC\"");
+
+	themeInit();
+	loadThemes();
+	xchat_printf(ph, "%s %s plugin loaded\n",*plugin_name, VERSION);
+
+	return 1;
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_command (ph, "MENU DEL \"Window/Display Current Song (MPC)\"");
+	xchat_print (ph, "mpcInfo plugin unloaded\n");
+	return 1;
+}
diff --git a/plugins/mpcinfo/oggInfo.c b/plugins/mpcinfo/oggInfo.c
new file mode 100644
index 00000000..83c2beb5
--- /dev/null
+++ b/plugins/mpcinfo/oggInfo.c
@@ -0,0 +1,122 @@
+/*
+ *  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.
+ */
+
+static int getOggInt(char *buff, int beg, int bytes){
+//if (DEBUG==1) putlog("getOggInt");
+	int ret=0;
+	int i;
+	for (i=0;i<bytes;i++){
+		if (buff[i+beg]>=0) ret+=buff[i+beg]*iPow(256,i);else ret+=(256+buff[i+beg])*iPow(256,i);
+		//printf("[%i]=%i\n",i,buff[i+beg]);
+	}
+	return ret;
+}
+
+static char *upperStr(char *text){
+//if (DEBUG==1) putlog("converting text to uc");
+    //printf("upperStr(%s)\n",text);
+	int i;
+	char *ret=(char*) malloc(sizeof(char)*(strlen(text)+1));
+	ret[strlen(text)]=0;
+	for (i=0;i<strlen(text);i++) ret[i]=toupper(text[i]);
+	//printf("Result: %s\n",ret);
+	return ret;
+}
+
+struct tagInfo getOggHeader(char *file){
+//if (DEBUG==1) putlog("reading ogg header");
+	char header[4096];
+	int i, c;
+	int h1pos, h3pos, maxBr, nomBr, minBr, pos, count, tagLen;
+	char *sub;
+	char *name;
+	char *val;
+	char *HEADLOC1, *HEADLOC3, *HEADLOC5;
+	FILE *f;
+	struct tagInfo info;
+
+	info.artist=NULL;
+	f = fopen(file,"rb");
+	if (f==NULL){
+       xchat_print(ph,"file not found while trying to read ogg header");
+       //if (DEBUG==1) putlog("file not found while trying to read ogg header");
+       return info;
+    }
+
+	for (i=0;i<4095;i++) {c=fgetc(f);header[i]=(char)c;}
+	fclose(f);
+	HEADLOC1="_vorbis";
+	HEADLOC1[0]=1;
+	HEADLOC3="_vorbis";
+	HEADLOC3[0]=3;
+	HEADLOC5="_vorbis";
+	HEADLOC5[0]=5;
+	h1pos=inStr(header,4096,HEADLOC1);
+	h3pos=inStr(header,4096,HEADLOC3);
+	//int h5pos=inStr(header,4096,HEADLOC5); //not needed
+	
+	//printf("loc1: %i\n",h1pos);printf("loc3: %i\n",h3pos);printf("loc5: %i\n",h5pos);
+	maxBr=getOggInt(header,h1pos+7+9,4);
+	nomBr=getOggInt(header,h1pos+7+13,4);
+	minBr=getOggInt(header,h1pos+7+17,4);
+	info.freq=getOggInt(header,h1pos+7+5,4);
+	info.mode=header[h1pos+7+4];
+	info.bitrate=nomBr;
+	if (((maxBr==nomBr)&&(nomBr=minBr))||((minBr==0)&&(maxBr==0))||((minBr=-1)&&(maxBr=-1)) )info.cbr=1;else info.cbr=0;
+	printf("bitrates: %i|%i|%i\n",maxBr,nomBr,minBr);
+	printf("freq: %i\n",info.freq);
+	pos=h3pos+7;
+	pos+=getOggInt(header,pos,4)+4;
+	count=getOggInt(header,pos,4);
+	//printf("tags: %i\n",count);
+	pos+=4;
+
+	info.artist=NULL;info.title=NULL;info.album=NULL;info.comment=NULL;info.genre=NULL;
+	for (i=0;i<count;i++){
+		tagLen=getOggInt(header,pos,4);
+		//printf("taglength: %i\n",tagLen);
+		sub=substring(header,pos+4,tagLen);
+		name=upperStr(substring(sub,0,inStr(sub,tagLen,"=")));
+		val=substring(sub,inStr(sub,tagLen,"=")+1,tagLen-inStr(sub,tagLen,"=")-1);
+		//printf("Tag: %s\n",sub);
+		//printf("Name: %s\n",name);
+		//printf("value: %s\n",val);
+		if (strcmp(name,"ARTIST")==0) info.artist=val;
+		if (strcmp(name,"TITLE")==0) info.title=val;
+		if (strcmp(name,"ALBUM")==0) info.album=val;
+		if (strcmp(name,"GENRE")==0) info.genre=val;
+		if (strcmp(name,"COMMENT")==0) info.comment=val;
+		pos+=4+tagLen;
+	}
+	if (info.artist==NULL) info.artist="";
+	if (info.album==NULL) info.album ="";
+	if (info.title==NULL) info.title="";
+	if (info.genre==NULL) info.genre="";
+	if (info.comment==NULL) info.comment="";
+	
+	printf("Artist: %s\nTitle: %s\nAlbum: %s\n",info.artist,info.title, info.album);
+	printf("Genre: %s\nComment: %s\nMode: %i\nCBR: %i\n",info.genre,info.comment,info.mode,info.cbr);
+	//if (DEBUG==1) putlog("ogg header readed");
+	return info;
+}
+
+/*
+void printOggInfo(char *file){
+	printf("Scanning Ogg-File for Informations: %s\n",file);
+	printf("size:\t%10d byte\n",getSize(file));
+	struct tagInfo info = getOggHeader(file);
+}
+*/
diff --git a/plugins/mpcinfo/theme.c b/plugins/mpcinfo/theme.c
new file mode 100644
index 00000000..000c00b1
--- /dev/null
+++ b/plugins/mpcinfo/theme.c
@@ -0,0 +1,136 @@
+/*
+ *  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.
+ */
+
+#include <time.h>
+
+struct theme{
+       int size;
+       char **line;
+};
+
+static struct theme notRunTheme;
+static struct theme titleTheme;
+static struct theme mp3Theme;
+static struct theme oggTheme;
+
+
+void themeInit(){
+     //if (DEBUG==1) putlog("init theme");
+     /*mp3Theme.size=0;oggTheme.size=0;cueTheme.size=0;streamTheme.size=0;etcTheme.size=0;
+     stopTheme.size=0;pauseTheme.size=0;*/
+     
+     notRunTheme.size=0;titleTheme.size=0;
+     srand((unsigned int)time((time_t *)NULL));
+     //if (DEBUG==1) putlog("theme init done");
+}
+
+void printTheme(struct theme data){
+     int i;
+     for (i=0;i<data.size;i++) xchat_printf(ph,"line[%i]=%s\n",i,data.line[i]);
+}
+
+void printThemes(){
+     xchat_printf(ph,"\nNotRun-Theme:\n");printTheme(notRunTheme);
+     xchat_printf(ph,"\nMP3-Theme:\n");printTheme(mp3Theme);
+     xchat_printf(ph,"\nOGG-Theme:\n");printTheme(oggTheme);
+     xchat_printf(ph,"\nTitle-Theme:\n");printTheme(titleTheme);
+}
+
+void cbFix(char *line){
+     //if (DEBUG==1) putlog("cbfix");
+     int i, j;
+     for (i=0;i<strlen(line);i++){
+         if (line[i]=='%'){
+            if ((line[i+1]=='C')||(line[i+1]=='B')||(line[i+1]=='U')||(line[i+1]=='O')||(line[i+1]=='R')){
+               if(line[i+1]=='C') line[i]=3;
+               if(line[i+1]=='B') line[i]=2;
+               if(line[i+1]=='U') line[i]=37;
+               if(line[i+1]=='O') line[i]=17;
+               if(line[i+1]=='R') line[i]=26;
+
+               for (j=i+1;j<strlen(line)-1;j++) line[j]=line[j+1];
+               line[strlen(line)-1]=0;
+            }
+         }
+     }
+     //if (DEBUG==1) putlog("cbfix done");
+}
+
+struct theme themeAdd(struct theme data, char *info){
+       //if (DEBUG==1) putlog("adding theme");
+       struct theme ret;
+       char **newLine=(char **)calloc(data.size+1,sizeof(char*));
+       int i;
+       for (i=0;i<data.size;i++) newLine[i]=data.line[i];
+       cbFix(info);
+       newLine[data.size]=info;
+       ret.line=newLine;ret.size=data.size+1;
+       //if (DEBUG==1) putlog("theme added");
+       return ret;
+}
+
+void loadThemes(){
+    char *hDir, *hFile, *line, *val;
+	FILE *f;
+	xchat_print(ph,"loading themes\n");
+    hDir=(char*)calloc(1024,sizeof(char));
+    strcpy(hDir,xchat_get_info(ph,"xchatdirfs"));
+    hFile=str3cat(hDir,"\\","mpcInfo.theme.txt");
+    f = fopen(hFile,"r");
+    if(f==NULL)
+	{
+		xchat_print(ph,"no theme in homedir, checking global theme");
+		f=fopen("mpcInfo.theme.txt","r");
+    }
+	//xchat_printf(ph,"file_desc: %p\n",f);
+	if (f==NULL) xchat_print(ph, "no theme found, using hardcoded\n");
+	else {
+		if (f > 0)
+		{
+			line=" ";
+		} else
+		{
+			line="\0";
+		}
+
+		while (line[0]!=0)
+		{
+			line=readLine(f);
+			val=split(line,'=');
+			printf("line: %s\n",line);
+			printf("val: %s\n",val);
+			if (strcmp(toUpper(line),"OFF_LINE")==0) notRunTheme=themeAdd(notRunTheme,val);
+			if (strcmp(toUpper(line),"TITLE_LINE")==0) titleTheme=themeAdd(titleTheme,val);
+			if (strcmp(toUpper(line),"MP3_LINE")==0) mp3Theme=themeAdd(mp3Theme,val);
+			if (strcmp(toUpper(line),"OGG_LINE")==0) mp3Theme=themeAdd(oggTheme,val);
+		}
+		fclose(f);
+		xchat_print(ph, "theme loaded successfull\n");
+	}
+	if (notRunTheme.size==0) notRunTheme=themeAdd(notRunTheme,"say Media Player Classic not running");
+	if (titleTheme.size==0) titleTheme=themeAdd(titleTheme,"say Playing %title in Media Player Classic");
+	if (mp3Theme.size==0) mp3Theme=themeAdd(mp3Theme,"me listens to %art with %tit from %alb [%gen|%br kbps|%frq kHz|%mode] in Media Player Classic ");
+	if (oggTheme.size==0) oggTheme=themeAdd(oggTheme,"me listens to %art with %tit from %alb [%gen|%br kbps|%frq kHz|%chan channels] in Media Player Classic ");
+	//mp3Theme=themeAdd(mp3Theme,"me listens to %art with %tit from %alb [%time|%length|%perc%|%br kbps|%frq kHz|%mode] in Media Player Classic ");
+}
+
+int rnd(int max){
+    return rand()%max;
+}
+
+char *randomLine(struct theme data){
+     return data.line[rnd(data.size)];
+}
diff --git a/plugins/nonbmp/makefile.mak b/plugins/nonbmp/makefile.mak
new file mode 100644
index 00000000..1c28610d
--- /dev/null
+++ b/plugins/nonbmp/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: nonbmp.obj nonbmp.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcnonbmp.dll /def:nonbmp.def nonbmp.obj

+

+nonbmp.def:

+	echo EXPORTS > nonbmp.def

+	echo xchat_plugin_init >> nonbmp.def

+	echo xchat_plugin_deinit >> nonbmp.def

+

+nonbmp.obj: nonbmp.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. nonbmp.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/nonbmp/nonbmp.c b/plugins/nonbmp/nonbmp.c
new file mode 100644
index 00000000..824c395e
--- /dev/null
+++ b/plugins/nonbmp/nonbmp.c
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;
+static const char name[] = "Non-BMP";
+static const char desc[] = "Replace non-BMP characters with replacement characters";
+static const char version[] = "1.0000";
+static int recursing = 0;
+
+static int filter(
+	char *word[],
+	char *word_eol[],
+	void *unused
+) {
+	gunichar *line;
+	gchar *utf8_line;
+	glong length;
+	glong index;
+
+	if( recursing ) {
+		return XCHAT_EAT_NONE;
+	}
+
+	/* the input has already been checked so we can use the _fast version */
+	line = g_utf8_to_ucs4_fast(
+		(char *)word_eol[1],
+		-1, /* NUL terminated input */
+		&length
+	);
+	
+	for( index = 0; index < length; index++ ) {
+		if( line[ index ] > 0xFFFF ) {
+			line[ index ] = 0xFFFD; /* replacement character */
+		}
+	}
+
+	utf8_line = g_ucs4_to_utf8(
+		line,
+		-1, /* NUL terminated input */
+		NULL, /* items read */
+		NULL, /* items written */
+		NULL  /* ignore conversion error */
+	);
+
+	if( utf8_line == NULL ) {
+		/* conversion failed ... I guess we are screwed? */
+		g_free( line );
+		return XCHAT_EAT_NONE;
+	}
+
+	recursing = 1;
+	xchat_commandf( ph, "RECV %s", utf8_line );
+	recursing = 0;
+
+	g_free( line );
+	g_free( utf8_line );
+	return XCHAT_EAT_ALL;
+}
+
+int xchat_plugin_init(
+	xchat_plugin *plugin_handle,
+	char **plugin_name,
+	char **plugin_desc,
+	char **plugin_version,
+	char *arg 
+) {
+/*	int index = 0;*/
+
+	ph = plugin_handle;
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	xchat_hook_server( ph, "RAW LINE", XCHAT_PRI_HIGHEST, filter, (void *)NULL );
+	xchat_printf (ph, "%s plugin loaded\n", name);
+	return 1;
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
\ No newline at end of file
diff --git a/plugins/perl/makefile-512.mak b/plugins/perl/makefile-512.mak
new file mode 100644
index 00000000..7f2fbe04
--- /dev/null
+++ b/plugins/perl/makefile-512.mak
@@ -0,0 +1,40 @@
+include "..\..\src\makeinc.mak"
+
+DIRENTLIB = ..\..\src\common\dirent-win32.lib
+TARGET = $(PERL512OUTPUT)
+
+all: $(TARGET)
+
+perl.def:
+	echo EXPORTS > perl.def
+	echo xchat_plugin_init >> perl.def
+	echo xchat_plugin_deinit >> perl.def
+	echo xchat_plugin_get_info >> perl.def
+
+perl.obj: perl.c
+	$(CC) $(CFLAGS) perl.c $(GLIB) /I$(PERL512PATH)\perl\lib\CORE /I.. /DPERL_DLL=\"$(PERL512LIB).dll\"
+
+perl512.def:
+	gendef $(PERL512PATH)\perl\bin\perl512.dll
+
+$(PERL512LIB).lib: perl512.def
+!ifdef X64
+	lib /nologo /machine:x64 /def:perl512.def
+!else
+	lib /nologo /machine:x86 /def:perl512.def
+!endif
+
+perl.c: xchat.pm.h
+
+xchat.pm.h: lib/Xchat.pm lib/IRC.pm
+	perl.exe generate_header
+
+$(TARGET): perl.obj perl.def $(PERL512LIB).lib
+	$(LINK) /DLL /out:$(TARGET) perl.obj $(LDFLAGS) $(PERL512LIB).lib /delayload:$(PERL512LIB).dll $(DIRENTLIB) delayimp.lib user32.lib shell32.lib advapi32.lib /def:perl.def
+
+clean:
+	@del $(TARGET)
+	@del *.obj
+	@del *.def
+	@del *.lib
+	@del *.exp
diff --git a/plugins/perl/makefile-514.mak b/plugins/perl/makefile-514.mak
new file mode 100644
index 00000000..4c8d0ebd
--- /dev/null
+++ b/plugins/perl/makefile-514.mak
@@ -0,0 +1,42 @@
+include "..\..\src\makeinc.mak"
+
+DIRENTLIB = ..\..\src\common\dirent-win32.lib
+TARGET = $(PERL514OUTPUT)
+
+all: $(TARGET)
+
+perl.def:
+	echo EXPORTS > perl.def
+	echo xchat_plugin_init >> perl.def
+	echo xchat_plugin_deinit >> perl.def
+	echo xchat_plugin_get_info >> perl.def
+
+# MSVC only supports __inline, while GCC only supports __inline__. This is defined incorretly
+# in lib\CORE\config.h in Strawberry Perl, see #define PERL_STATIC_INLINE static __inline__
+perl.obj: perl.c
+	$(CC) $(CFLAGS) perl.c $(GLIB) /I$(PERL514PATH)\perl\lib\CORE /I.. /DPERL_DLL=\"$(PERL514LIB).dll\" /D__inline__=__inline
+
+perl514.def:
+	gendef $(PERL514PATH)\perl\bin\perl514.dll
+
+$(PERL514LIB).lib: perl514.def
+!ifdef X64
+	lib /nologo /machine:x64 /def:perl514.def
+!else
+	lib /nologo /machine:x86 /def:perl514.def
+!endif
+
+perl.c: xchat.pm.h
+
+xchat.pm.h: lib/Xchat.pm lib/IRC.pm
+	perl.exe generate_header
+
+$(TARGET): perl.obj perl.def $(PERL514LIB).lib
+	$(LINK) /DLL /out:$(TARGET) perl.obj $(LDFLAGS) $(PERL514LIB).lib /delayload:$(PERL514LIB).dll $(DIRENTLIB) delayimp.lib user32.lib shell32.lib advapi32.lib /def:perl.def
+
+clean:
+	@del $(TARGET)
+	@del *.obj
+	@del *.def
+	@del *.lib
+	@del *.exp
diff --git a/plugins/perl/perl.c b/plugins/perl/perl.c
index 1be7562e..719ef292 100644
--- a/plugins/perl/perl.c
+++ b/plugins/perl/perl.c
@@ -22,12 +22,15 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <dirent.h>
 #ifdef ENABLE_NLS
 #include <locale.h>
 #endif
 #ifdef WIN32
 #include <windows.h>
+#define  _INC_DIRENT /* disable inclusion of perl's dirent.h, we use an own version for win32 */
+#include "../../src/common/dirent-win32.h"
+#else
+#include <dirent.h>
 #endif
 
 #undef PACKAGE
@@ -1342,7 +1345,11 @@ perl_load_file (char *filename)
 			if (GetLastError () == ERROR_BAD_EXE_FORMAT)
 				/* http://forum.xchat.org/viewtopic.php?t=3277 */
 				thread_mbox ("Cannot use this " PERL_DLL "\n\n"
-								 "32-bit ActivePerl is required.");
+#ifdef _WIN64
+								 "64-bit Strawberry Perl is required.");
+#else
+								 "32-bit Strawberry Perl is required.");
+#endif
 			else {
 				/* a lot of people install this old version */
 				lib = LoadLibraryA ("perl56.dll");
diff --git a/plugins/plugin20.html b/plugins/plugin20.html
index 787c048b..fcdff2ed 100644
--- a/plugins/plugin20.html
+++ b/plugins/plugin20.html
@@ -81,6 +81,13 @@ margin-right: 32px;
 <br><a href="#xchat_strip">xchat_strip</a>
 <br><a href="#xchat_free">xchat_free</a>
 <br>
+<br><a href="#xchat_pluginpref_set_str">xchat_pluginpref_set_str</a>
+<br><a href="#xchat_pluginpref_get_str">xchat_pluginpref_get_str</a>
+<br><a href="#xchat_pluginpref_set_int">xchat_pluginpref_set_int</a>
+<br><a href="#xchat_pluginpref_get_int">xchat_pluginpref_get_int</a>
+<br><a href="#xchat_pluginpref_delete">xchat_pluginpref_delete</a>
+<br><a href="#xchat_pluginpref_list">xchat_pluginpref_list</a>
+<br>
 <br><a href="#lists">xchat_list_get</a>
 <br><a href="#lists">xchat_list_free</a>
 <br><a href="#lists">xchat_list_fields</a> (not documented yet)
@@ -998,5 +1005,137 @@ A newly allocated string or NULL for failure. You must free this string with xch
 
 <br><br>
 
+<h3><a class=cmd name="xchat_pluginpref_set_str">&nbsp;xchat_pluginpref_set_str()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_set_str (xchat_plugin *ph, const char *var, const char *value);
+<br>
+<br><b>Description:</b> Saves a plugin-specific setting with string value to a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>var:</b> Name of the setting to save.
+<br><b>value:</b> String value of the the setting.
+<br>
+</blockquote>
+<b>Returns:</b> 1 for success, 0 for failure.
+<br><br><b>Example:</b>
+<blockquote>
+<pre>int xchat_plugin_init (xchat_plugin *plugin_handle,
+			char **plugin_name,
+			char **plugin_desc,
+			char **plugin_version,
+			char *arg)
+{
+	ph = plugin_handle;
+	*plugin_name = "Tester Thingie";
+	*plugin_desc = "Testing stuff";
+	*plugin_version = "1.0";
+
+	xchat_pluginpref_set_str (ph, "myvar1", "I want to save this string!");
+	xchat_pluginpref_set_str (ph, "myvar2", "This is important, too.");
+
+	return 1;       /* return 1 for success */
+}</pre>
+</blockquote>
+In the example above, the settings will be saved to the plugin_tester_thingie.conf file, and its content will be:
+<blockquote>
+<pre>myvar1 = I want to save this string!
+myvar2 = This is important, too.</pre>
+</blockquote>
+You should never need to edit this file manually.
+<br><br><br>
+
+<h3><a class=cmd name="xchat_pluginpref_get_str">&nbsp;xchat_pluginpref_get_str()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_get_str (xchat_plugin *ph, const char *var, char *dest);
+<br>
+<br><b>Description:</b> Loads a plugin-specific setting with string value from a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>var:</b> Name of the setting to load.
+<br><b>dest:</b> Array to save the loaded setting's string value to.
+<br>
+</blockquote>
+<b>Returns:</b> 1 for success, 0 for failure.
+<br><br><br>
+
+<h3><a class=cmd name="xchat_pluginpref_set_int">&nbsp;xchat_pluginpref_set_int()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_set_int (xchat_plugin *ph, const char *var, int value);
+<br>
+<br><b>Description:</b> Saves a plugin-specific setting with decimal value to a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>var:</b> Name of the setting to save.
+<br><b>value:</b> Decimal value of the the setting.
+<br>
+</blockquote>
+<b>Returns:</b> 1 for success, 0 for failure.
+<br><br><b>Example:</b>
+<blockquote>
+<pre>static int saveint_cb (char *word[], char *word_eol[], void *user_data)
+{
+	int buffer = atoi (word[2]);
+
+	if (buffer > 0 && buffer < INT_MAX)
+	{
+		if (xchat_pluginpref_set_int (ph, "myint1", buffer))
+		{
+			xchat_printf (ph, "Setting successfully saved!\n");
+		}
+		else
+		{
+			xchat_printf (ph, "Error while saving!\n");
+		}
+	}
+	else
+	{
+		xchat_printf (ph, "Invalid input!\n");
+	}
+
+	return XCHAT_EAT_XCHAT;
+}</pre>
+</blockquote>
+You only need these kind of complex checks if you're saving user input, which can be non-numeric.
+<br><br><br>
+
+<h3><a class=cmd name="xchat_pluginpref_get_int">&nbsp;xchat_pluginpref_get_int()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_get_int (xchat_plugin *ph, const char *var);
+<br>
+<br><b>Description:</b> Loads a plugin-specific setting with decimal value from a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>var:</b> Name of the setting to load.
+<br>
+</blockquote>
+<b>Returns:</b> The decimal value of the requested setting upon success, -1 for failure.
+<br><br><br>
+
+<h3><a class=cmd name="xchat_pluginpref_delete">&nbsp;xchat_pluginpref_delete()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_delete (xchat_plugin *ph, const char *var);
+<br>
+<br><b>Description:</b> Deletes a plugin-specific setting from a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>var:</b> Name of the setting to delete.
+<br>
+</blockquote>
+<b>Returns:</b> 1 for success, 0 for failure. If the given setting didn't exist, it also returns 1, so 1 only indicates that the setting won't exist after the call.
+<br><br><br>
+
+<h3><a class=cmd name="xchat_pluginpref_list">&nbsp;xchat_pluginpref_list()&nbsp;</a><small>(new for 2.8.10)</small></h3>
+<b>Prototype:</b> int xchat_pluginpref_list (xchat_plugin *ph, char *dest);
+<br>
+<br><b>Description:</b> Builds a comma-separated list of the currently saved settings from a plugin-specific config file.
+<br>
+<br><b>Arguments:</b>
+<blockquote><b>ph:</b> Plugin handle (as given to xchat_plugin_init).
+<br><b>dest:</b> Array to save the list to.
+<br>
+</blockquote>
+<b>Returns:</b> 1 for success, 0 for failure (nonexistent, empty or inaccessible config file).
+<br><br><br>
+
 </body>
 </html>
diff --git a/plugins/python/makefile.mak b/plugins/python/makefile.mak
new file mode 100644
index 00000000..bc004577
--- /dev/null
+++ b/plugins/python/makefile.mak
@@ -0,0 +1,25 @@
+include "..\..\src\makeinc.mak"
+
+DIRENTLIB = ..\..\src\common\dirent-win32.lib
+TARGET = $(PYTHONOUTPUT)
+
+all: $(TARGET)
+
+python.def:
+	echo EXPORTS > python.def
+	echo xchat_plugin_init >> python.def
+	echo xchat_plugin_deinit >> python.def
+	echo xchat_plugin_get_info >> python.def
+
+python.obj: python.c
+	$(CC) $(CFLAGS) /I.. /Dusleep=_sleep /DPATH_MAX=255 python.c $(GLIB) /I$(PYTHONPATH)\include /DPYTHON_DLL=\"$(PYTHONLIB).dll\"
+
+$(TARGET): python.obj python.def
+	$(LINK) /dll /out:$(TARGET) $(LDFLAGS) python.obj /libpath:$(PYTHONPATH)\libs $(PYTHONLIB).lib $(DIRENTLIB) $(LIBS) /def:python.def
+
+clean:
+	del $(TARGET)
+	del *.obj
+	del python.def
+	del *.lib
+	del *.exp
diff --git a/plugins/python/python.c b/plugins/python/python.c
index fd682082..dcf4fc8f 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -53,10 +53,16 @@
 
 #include <glib.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdlib.h>
 #include <sys/types.h>
+
+#ifdef WIN32
+#include "../../src/common/dirent-win32.h"
+#include "../../config.h"
+#else
+#include <unistd.h>
 #include <dirent.h>
+#endif
 
 #include "xchat-plugin.h"
 #include "Python.h"
@@ -68,7 +74,7 @@
 
 #ifdef WIN32
 #undef WITH_THREAD /* Thread support locks up xchat on Win32. */
-#define VERSION "0.8/2.4"	/* Linked to python24.dll */
+#define VERSION "0.8/2.7"	/* Linked to python27.dll */
 #else
 #define VERSION "0.8"
 #endif
diff --git a/plugins/tcl/makefile.mak b/plugins/tcl/makefile.mak
new file mode 100644
index 00000000..c88f5c4f
--- /dev/null
+++ b/plugins/tcl/makefile.mak
@@ -0,0 +1,22 @@
+include "..\..\src\makeinc.mak"
+
+TARGET = $(TCLOUTPUT)
+
+all: $(TARGET)
+
+tcl.def:
+	echo EXPORTS > tcl.def
+	echo xchat_plugin_init >> tcl.def
+	echo xchat_plugin_deinit >> tcl.def
+	echo xchat_plugin_get_info >> tcl.def
+
+tclplugin.obj: tclplugin.c
+	$(CC) $(CFLAGS) /I.. tclplugin.c /I$(TCLPATH)\include /DTCL_DLL=\"$(TCLLIB).dll\"
+
+$(TARGET): tclplugin.obj tcl.def
+	$(LINK) /dll /out:$(TARGET) $(LDFLAGS) tclplugin.obj /libpath:$(TCLPATH)\lib $(TCLLIB).lib /delayload:$(TCLLIB).dll delayimp.lib /def:tcl.def
+
+clean:
+	del $(TARGET)
+	del *.obj
+	del tcl.def
diff --git a/plugins/tcl/tclplugin.c b/plugins/tcl/tclplugin.c
index 17dc7556..920a48ad 100644
--- a/plugins/tcl/tclplugin.c
+++ b/plugins/tcl/tclplugin.c
@@ -2221,7 +2221,7 @@ int xchat_plugin_init(xchat_plugin * plugin_handle, char **plugin_name, char **p
 #ifdef WIN32
     lib = LoadLibraryA(TCL_DLL);
     if (!lib) {
-        xchat_print(ph, "You must have ActiveTCL installed in order to run Tcl scripts.\n" "http://aspn.activestate.com/ASPN/Tcl/\n" "Make sure Tcl's bin directory is in your PATH.\n\n");
+        xchat_print(ph, "You must have ActiveTCL 8.5 installed in order to run Tcl scripts.\n" "http://www.activestate.com/activetcl/downloads\n" "Make sure Tcl's bin directory is in your PATH.\n");
         return 0;
     }
     FreeLibrary(lib);
diff --git a/plugins/upd/makefile.mak b/plugins/upd/makefile.mak
new file mode 100644
index 00000000..34b54cb8
--- /dev/null
+++ b/plugins/upd/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: upd.obj upd.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcupd.dll /def:upd.def upd.obj

+

+upd.def:

+	echo EXPORTS > upd.def

+	echo xchat_plugin_init >> upd.def

+	echo xchat_plugin_deinit >> upd.def

+

+upd.obj: upd.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. upd.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/upd/upd.c b/plugins/upd/upd.c
new file mode 100644
index 00000000..1659162c
--- /dev/null
+++ b/plugins/upd/upd.c
@@ -0,0 +1,226 @@
+/* XChat-WDK
+ * Copyright (c) 2010-2011 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <windows.h>
+#include <wininet.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+static const char name[] = "Update Checker";
+static const char desc[] = "Check for XChat-WDK updates automatically";
+static const char version[] = "2.1";
+
+static char*
+check_version ()
+{
+#if 0
+	HINTERNET hINet, hFile;
+	hINet = InternetOpen ("Update Checker", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+
+	if (!hINet)
+	{
+		return "Unknown";
+	}
+
+	hFile = InternetOpenUrl (hINet,
+							"http://xchat-wdk.googlecode.com/git/version.txt?r=wdk",
+							NULL,
+							0,
+							INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD,
+							0);
+	if (hFile)
+	{
+		static char buffer[1024];
+		DWORD dwRead;
+		while (InternetReadFile (hFile, buffer, 1023, &dwRead))
+		{
+			if (dwRead == 0)
+			{
+				break;
+			}
+			buffer[dwRead] = 0;
+		}
+
+		InternetCloseHandle (hFile);
+		InternetCloseHandle (hINet);
+		return buffer;
+	}
+
+	InternetCloseHandle (hINet);
+	return "Unknown";
+#endif
+
+	/* Google Code's messing up with requests, use HTTP/1.0 as suggested. More info:
+
+	   http://code.google.com/p/support/issues/detail?id=6095
+
+	   Of course it would be still too simple, coz IE will override settings, so
+	   you have to disable HTTP/1.1 manually and globally. More info:
+
+	   http://support.microsoft.com/kb/258425
+
+	   So this code's basically useless since disabling HTTP/1.1 will work with the
+	   above code too.
+
+	   Update: a Connection: close header seems to disable chunked encoding.
+	*/
+
+	HINTERNET hOpen, hConnect, hResource;
+
+	hOpen = InternetOpen (TEXT ("Update Checker"),
+						INTERNET_OPEN_TYPE_PRECONFIG,
+						NULL,
+						NULL,
+						0);
+	if (!hOpen)
+	{
+		return "Unknown";
+	}
+
+	hConnect = InternetConnect (hOpen,
+								TEXT ("xchat-wdk.googlecode.com"),
+								INTERNET_INVALID_PORT_NUMBER,
+								NULL,
+								NULL,
+								INTERNET_SERVICE_HTTP,
+								0,
+								0);
+	if (!hConnect)
+	{
+		InternetCloseHandle (hOpen);
+		return "Unknown";
+	}
+
+	hResource = HttpOpenRequest (hConnect,
+								TEXT ("GET"),
+								TEXT ("/git/version.txt?r=wdk"),
+								TEXT ("HTTP/1.0"),
+								NULL,
+								NULL,
+								INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTH,
+								0);
+	if (!hResource)
+	{
+		InternetCloseHandle (hConnect);
+		InternetCloseHandle (hOpen);
+		return "Unknown";
+	}
+	else
+	{
+		static char buffer[1024];
+		DWORD dwRead;
+
+		HttpAddRequestHeaders (hResource, TEXT ("Connection: close\r\n"), -1L, HTTP_ADDREQ_FLAG_ADD);	/* workaround for GC bug */
+		HttpSendRequest (hResource, NULL, 0, NULL, 0);
+
+		while (InternetReadFile (hResource, buffer, 1023, &dwRead))
+		{
+			if (dwRead == 0)
+			{
+				break;
+			}
+			buffer[dwRead] = 0;
+		}
+
+		InternetCloseHandle (hResource);
+		InternetCloseHandle (hConnect);
+		InternetCloseHandle (hOpen);
+		return buffer;
+	}
+}
+
+static int
+print_version ()
+{
+	char *version = check_version ();
+
+	if (strcmp (version, xchat_get_info (ph, "wdk_version")) == 0)
+	{
+		xchat_printf (ph, "You have the latest version of XChat-WDK installed!\n");
+	}
+	else if (strcmp (version, "Unknown") == 0)
+	{
+		xchat_printf (ph, "Unable to check for XChat-WDK updates!\n");
+	}
+	else
+	{
+#ifdef _WIN64 /* use this approach, the wProcessorArchitecture method always returns 0 (=x86) for some reason */
+		xchat_printf (ph, "An XChat-WDK update is available! You can download it from here:\nhttp://xchat-wdk.googlecode.com/files/XChat-WDK%%20%s%%20x64.exe\n", version);
+#else
+		xchat_printf (ph, "An XChat-WDK update is available! You can download it from here:\nhttp://xchat-wdk.googlecode.com/files/XChat-WDK%%20%s%%20x86.exe\n", version);
+#endif
+	}
+
+	return XCHAT_EAT_XCHAT;
+}
+
+static int
+print_version_quiet (void *userdata)
+{
+	char *version = check_version ();
+
+	/* if it's not the current version AND not network error */
+	if (!(strcmp (version, xchat_get_info (ph, "wdk_version")) == 0) && !(strcmp (version, "Unknown") == 0))
+	{
+#ifdef _WIN64 /* use this approach, the wProcessorArchitecture method always returns 0 (=x86) for plugins for some reason */
+		xchat_printf (ph, "An XChat-WDK update is available! You can download it from here:\nhttp://xchat-wdk.googlecode.com/files/XChat-WDK%%20%s%%20x64.exe\n", version);
+#else
+		xchat_printf (ph, "An XChat-WDK update is available! You can download it from here:\nhttp://xchat-wdk.googlecode.com/files/XChat-WDK%%20%s%%20x86.exe\n", version);
+#endif
+		/* print update url once, then stop the timer */
+		return 0;
+	}
+	/* keep checking */
+	return 1;
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	xchat_hook_command (ph, "UPDCHK", XCHAT_PRI_NORM, print_version, 0, 0);
+	xchat_command (ph, "MENU -ietc\\download.png ADD \"Help/Check for Updates\" \"UPDCHK\"");
+	xchat_printf (ph, "%s plugin loaded\n", name);
+
+	/* only start the timer if there's no update available during startup */
+	if (print_version_quiet (NULL))
+	{
+		/* check for updates every 6 hours */
+		xchat_hook_timer (ph, 21600000, print_version_quiet, NULL);
+	}
+
+	return 1;       /* return 1 for success */
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_command (ph, "MENU DEL \"Help/Check for updates\"");
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
diff --git a/plugins/winamp/makefile.mak b/plugins/winamp/makefile.mak
new file mode 100644
index 00000000..79adf87e
--- /dev/null
+++ b/plugins/winamp/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: winamp.obj winamp.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcwinamp.dll /def:winamp.def winamp.obj

+

+winamp.def:

+	echo EXPORTS > winamp.def

+	echo xchat_plugin_init >> winamp.def

+	echo xchat_plugin_deinit >> winamp.def

+

+winamp.obj: winamp.c makefile.mak

+	cl $(CFLAGS) /I.. winamp.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/winamp/winamp.c b/plugins/winamp/winamp.c
new file mode 100644
index 00000000..7201a875
--- /dev/null
+++ b/plugins/winamp/winamp.c
@@ -0,0 +1,189 @@
+/********************* Winamp Plugin 0.3******************************
+ *
+ *   Distribution: GPL
+ *
+ *   Originally written by: Leo - leo.nard@free.fr
+ *   Modified by: SilvereX - SilvereX@karklas.mif.vu.lt
+ *   Modified again by: Derek Buitenhuis - daemon404@gmail.com
+ *   Modified yet again by: Berke Viktor - berkeviktor@aol.com
+ *********************************************************************/
+
+#include "windows.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xchat-plugin.h"
+
+#define PLAYING 1
+#define PAUSED 3
+
+static xchat_plugin *ph;   /* plugin handle */
+
+BOOL winamp_found = FALSE;
+
+int status = 0;
+
+/* Slightly modified from X-Chat's log_escape_strcpy */
+static char *
+song_strcpy (char *dest, char *src)
+{
+	while (*src)
+	{
+		*dest = *src;
+		dest++;
+		src++;
+
+		if (*src == '%')
+		{
+			dest[0] = '%';
+			dest++;
+		}
+	}
+
+	dest[0] = 0;
+	return dest - 1;
+}
+
+static int
+winamp(char *word[], char *word_eol[], void *userdata)
+{
+
+char current_play[2048], *p;
+char p_esc[2048];
+char cur_esc[2048];
+char truc[2048];
+HWND hwndWinamp = FindWindow("Winamp v1.x",NULL);
+
+    if (hwndWinamp)
+	{
+	    {
+	        if (!stricmp("PAUSE", word[2]))
+			{
+			   if (SendMessage(hwndWinamp,WM_USER, 0, 104))
+				{
+			   	   SendMessage(hwndWinamp, WM_COMMAND, 40046, 0);
+			
+			       if (SendMessage(hwndWinamp, WM_USER, 0, 104) == PLAYING)
+			   	       xchat_printf(ph, "Winamp: playing");
+			       else
+                       xchat_printf(ph, "Winamp: paused");
+				}
+            }
+			else
+		        if (!stricmp("STOP", word[2]))
+			    {
+			       SendMessage(hwndWinamp, WM_COMMAND, 40047, 0);
+			       xchat_printf(ph, "Winamp: stopped");
+			    }
+			else
+			    if (!stricmp("PLAY", word[2]))
+			    {
+			         SendMessage(hwndWinamp, WM_COMMAND, 40045, 0);
+			         xchat_printf(ph, "Winamp: playing");
+			    }
+        	else
+
+			    if (!stricmp("NEXT", word[2]))
+			    {
+			         SendMessage(hwndWinamp, WM_COMMAND, 40048, 0);
+			         xchat_printf(ph, "Winamp: next playlist entry");
+			    }
+			else
+
+                if (!stricmp("PREV", word[2]))
+			    {
+			         SendMessage(hwndWinamp, WM_COMMAND, 40044, 0);
+			         xchat_printf(ph, "Winamp: previous playlist entry");
+			    }
+		    else
+
+                if (!stricmp("START", word[2]))
+			    {
+			         SendMessage(hwndWinamp, WM_COMMAND, 40154, 0);
+			         xchat_printf(ph, "Winamp: playlist start");
+			    }
+
+		    else
+
+                if (!word_eol[2][0])
+			    {
+					GetWindowText(hwndWinamp, current_play, sizeof(current_play));
+
+					if (strchr(current_play, '-'))
+					{
+	
+					p = current_play + strlen(current_play) - 8;
+					while (p >= current_play)
+					{
+						if (!strnicmp(p, "- Winamp", 8)) break;
+							p--;
+					}
+
+					if (p >= current_play) p--;
+	
+					while (p >= current_play && *p == ' ') p--;
+						*++p=0;
+	
+	
+					p = strchr(current_play, '.') + 1;
+
+ 					song_strcpy(p_esc, p);
+ 					song_strcpy(cur_esc, current_play);
+	
+					if (p)
+					{
+						sprintf(truc, "me is now playing:%s", p_esc);
+					}
+					else
+					{
+						sprintf(truc, "me is now playing:%s", cur_esc);
+					}
+	
+	   				xchat_commandf(ph, truc);
+	
+				}
+				else xchat_print(ph, "Winamp: Nothing being played.");
+			}
+		    else
+                xchat_printf(ph, "Usage: /WINAMP [PAUSE|PLAY|STOP|NEXT|PREV|START]\n");
+         }
+
+	}
+	else
+	{
+       xchat_print(ph, "Winamp not found.\n");
+	}
+	return XCHAT_EAT_ALL;
+}
+
+int
+xchat_plugin_init(xchat_plugin *plugin_handle,
+                      char **plugin_name,
+                      char **plugin_desc,
+                      char **plugin_version,
+                      char *arg)
+{
+	/* we need to save this for use with any xchat_* functions */
+	ph = plugin_handle;
+
+	*plugin_name = "Winamp";
+	*plugin_desc = "Winamp plugin for XChat";
+	*plugin_version = "0.5";
+
+	xchat_hook_command (ph, "WINAMP", XCHAT_PRI_NORM, winamp, "Usage: /WINAMP [PAUSE|PLAY|STOP|NEXT|PREV|START] - control Winamp or show what's currently playing", 0);
+   	xchat_command (ph, "MENU -ietc\\music.png ADD \"Window/Display Current Song (Winamp)\" \"WINAMP\"");
+
+	xchat_print (ph, "Winamp plugin loaded\n");
+
+	return 1;       /* return 1 for success */
+}
+
+int
+xchat_plugin_deinit(void)
+{
+	xchat_command (ph, "MENU DEL \"Window/Display Current Song (Winamp)\"");
+	xchat_print (ph, "Winamp plugin unloaded\n");
+	return 1;
+}
diff --git a/plugins/winsys/makefile.mak b/plugins/winsys/makefile.mak
new file mode 100644
index 00000000..31f24eb1
--- /dev/null
+++ b/plugins/winsys/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: winsys.obj winsys.def

+	link $(LDFLAGS) $(LIBS) /NODEFAULTLIB:comsupp.lib wbemuuid.lib vccomsup.lib /dll /out:xcwinsys.dll /def:winsys.def winsys.obj

+

+winsys.def:

+	echo EXPORTS > winsys.def

+	echo xchat_plugin_init >> winsys.def

+	echo xchat_plugin_deinit >> winsys.def

+

+winsys.obj: winsys.cpp makefile.mak

+	cl $(CFLAGS) $(GLIB) /DUNICODE /D_UNICODE /Zc:wchar_t- /I.. winsys.cpp

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/winsys/winsys.cpp b/plugins/winsys/winsys.cpp
new file mode 100644
index 00000000..398767d0
--- /dev/null
+++ b/plugins/winsys/winsys.cpp
@@ -0,0 +1,415 @@
+/* XChat-WDK
+ * Copyright (c) 2011 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+#include <comutil.h>
+#include <wbemidl.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+static char name[] = "WinSys";
+static char desc[] = "Display info about your hardware and OS";
+static char version[] = "1.1";
+static int firstRun;
+static char *wmiOs;
+static char *wmiCpu;
+static char *wmiVga;
+
+static int
+getCpuArch (void)
+{
+	OSVERSIONINFOEX osvi;
+	SYSTEM_INFO si;
+
+	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+	GetVersionEx ((LPOSVERSIONINFOW) &osvi);
+
+	GetSystemInfo (&si);
+
+	if (si.wProcessorArchitecture == 9)
+	{
+		return 64;
+	}
+	else
+	{
+		return 86;
+	}
+}
+
+#if 0
+/* use WMI instead, wProcessorArchitecture displays current binary arch instead of OS arch anyway */
+static char *
+getOsName (void)
+{
+	static char winver[32];
+	double mhz;
+	OSVERSIONINFOEX osvi;
+	SYSTEM_INFO si;
+
+	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+	GetVersionEx ((LPOSVERSIONINFOW) &osvi);
+
+	GetSystemInfo (&si);
+
+	strcpy (winver, "Windows ");
+
+	switch (osvi.dwMajorVersion)
+	{
+		case 5:
+			switch (osvi.dwMinorVersion)
+			{
+				case 1:
+					strcat (winver, "XP");
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "XP x64 Edition");
+					}
+					else
+					{
+						if (GetSystemMetrics(SM_SERVERR2) == 0)
+						{
+							strcat (winver, "Server 2003");
+						}
+						else
+						{
+							strcat (winver, "Server 2003 R2");
+						}
+					}
+					break;
+			}
+			break;
+		case 6:
+			switch (osvi.dwMinorVersion)
+			{
+				case 0:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "Vista");
+					}
+					else
+					{
+						strcat (winver, "Server 2008");
+					}
+					break;
+				case 1:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "7");
+					}
+					else
+					{
+						strcat (winver, "Server 2008 R2");
+					}
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "8");
+					}
+					else
+					{
+						strcat (winver, "8 Server");
+					}
+					break;
+			}
+			break;
+	}
+
+	if (si.wProcessorArchitecture == 9)
+	{
+		strcat (winver, " (x64)");
+	}
+	else
+	{
+		strcat (winver, " (x86)");
+	}
+
+	return winver;
+}
+
+/* x86-only, SDK-only, use WMI instead */
+static char *
+getCpuName (void)
+{
+	// Get extended ids.
+	unsigned int nExIds;
+	unsigned int i;
+	int CPUInfo[4] = {-1};
+	static char CPUBrandString[128];
+
+	__cpuid (CPUInfo, 0x80000000);
+	nExIds = CPUInfo[0];
+
+	/* Get the information associated with each extended ID. */
+	for (i=0x80000000; i <= nExIds; ++i)
+	{
+		__cpuid (CPUInfo, i);
+
+		if (i == 0x80000002)
+		{
+			memcpy (CPUBrandString, CPUInfo, sizeof (CPUInfo));
+		}
+		else if (i == 0x80000003)
+		{
+			memcpy( CPUBrandString + 16, CPUInfo, sizeof (CPUInfo));
+		}
+		else if (i == 0x80000004)
+		{
+			memcpy (CPUBrandString + 32, CPUInfo, sizeof (CPUInfo));
+		}
+	}
+
+	return CPUBrandString;
+}
+#endif
+
+static char *
+getCpuMhz (void)
+{
+	HKEY hKey;
+	int result;
+	int data;
+	int dataSize;
+	double cpuspeed;
+	static char buffer[16];
+	const char *cpuspeedstr;
+
+	if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("Hardware\\Description\\System\\CentralProcessor\\0"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+	{
+		dataSize = sizeof (data);
+		result = RegQueryValueEx (hKey, TEXT("~MHz"), 0, 0, (LPBYTE)&data, (LPDWORD)&dataSize);
+		RegCloseKey (hKey);
+		if (result == ERROR_SUCCESS)
+		{
+			cpuspeed = ( data > 1000 ) ? data / 1000 : data;
+			cpuspeedstr = ( data > 1000 ) ? "GHz" : "MHz";
+			sprintf (buffer, "%.2f %s", cpuspeed, cpuspeedstr);
+		}
+	}
+
+	return buffer;
+}
+
+static char *
+getMemoryInfo (void)
+{
+	static char buffer[32];
+	MEMORYSTATUSEX meminfo;
+
+	meminfo.dwLength = sizeof (meminfo);
+	GlobalMemoryStatusEx (&meminfo);
+
+	sprintf (buffer, "%I64d MB Total (%I64d MB Free)", meminfo.ullTotalPhys / 1024 / 1024, meminfo.ullAvailPhys / 1024 / 1024);
+
+	return buffer;
+}
+
+static char *
+getWmiInfo (int mode)
+{
+	/* for more details about this wonderful API, see 
+	http://msdn.microsoft.com/en-us/site/aa394138
+	http://msdn.microsoft.com/en-us/site/aa390423
+	http://msdn.microsoft.com/en-us/library/windows/desktop/aa394138%28v=vs.85%29.aspx
+	http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/d6420012-e432-4964-8506-6f6b65e5a451
+	*/
+
+	char *buffer = (char *) malloc (128);
+	HRESULT hres;
+	HRESULT hr;
+	IWbemLocator *pLoc = NULL;
+	IWbemServices *pSvc = NULL;
+	IEnumWbemClassObject *pEnumerator = NULL;
+	IWbemClassObject *pclsObj;
+	ULONG uReturn = 0;
+
+	hres =  CoInitializeEx (0, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY);
+
+	if (FAILED (hres))
+	{
+		strcpy (buffer, "Error Code 0");
+		return buffer;
+	}
+
+	hres =  CoInitializeSecurity (NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
+
+	/* mysteriously failing after the first execution, but only when used as a plugin, skip it */
+	/*if (FAILED (hres))
+	{
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 1");
+		return buffer;
+	}*/
+
+	hres = CoCreateInstance (CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
+
+	if (FAILED (hres))
+	{
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 2");
+		return buffer;
+	}
+
+	hres = pLoc->ConnectServer (_bstr_t (L"root\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
+
+	if (FAILED (hres))
+	{
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 3");
+		return buffer;
+	}
+
+	hres = CoSetProxyBlanket (pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
+
+	if (FAILED (hres))
+	{
+		pSvc->Release ();
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 4");
+		return buffer;
+	}
+
+	switch (mode)
+	{
+		case 0:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+		case 1:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_Processor"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+		case 2:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_VideoController"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+
+	}
+
+	if (FAILED (hres))
+	{
+		pSvc->Release ();
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 5");
+		return buffer;
+	}
+
+	while (pEnumerator)
+	{
+		hr = pEnumerator->Next (WBEM_INFINITE, 1, &pclsObj, &uReturn);
+		if (0 == uReturn)
+		{
+			break;
+		}
+		VARIANT vtProp;
+		switch (mode)
+		{
+			case 0:
+				hr = pclsObj->Get (L"Caption", 0, &vtProp, 0, 0);
+				break;
+			case 1:
+				hr = pclsObj->Get (L"Name", 0, &vtProp, 0, 0);
+				break;
+			case 2:
+				hr = pclsObj->Get (L"Name", 0, &vtProp, 0, 0);
+				break;
+		}
+		WideCharToMultiByte (CP_ACP, 0, vtProp.bstrVal, -1, buffer, SysStringLen (vtProp.bstrVal)+1, NULL, NULL);
+		VariantClear (&vtProp);
+    }
+
+	pSvc->Release ();
+	pLoc->Release ();
+	pEnumerator->Release ();
+	pclsObj->Release ();
+	CoUninitialize ();
+	return buffer;
+}
+
+static int
+printInfo (char *word[], char *word_eol[], void *user_data)
+{
+	/* query WMI info only at the first time WinSys is called, then cache it to save time */
+	if (firstRun)
+	{
+		xchat_printf (ph, "%s first execution, querying and caching WMI info...\n", name);
+		wmiOs = getWmiInfo (0);
+		wmiCpu = getWmiInfo (1);
+		wmiVga = getWmiInfo (2);
+		firstRun = 0;
+	}
+	if (xchat_list_int (ph, NULL, "type") >= 2)
+	{
+		/* uptime will work correctly for up to 50 days, should be enough */
+		xchat_commandf (ph, "ME ** WinSys ** Client: XChat-WDK %s (x%d) ** OS: %s ** CPU: %s (%s) ** RAM: %s ** VGA: %s ** Uptime: %.2f Hours **",
+			xchat_get_info (ph, "wdk_version"),
+			getCpuArch (),
+			wmiOs,
+			wmiCpu,
+			getCpuMhz (),
+			getMemoryInfo (),
+			wmiVga, (float) GetTickCount() / 1000 / 60 / 60);
+	}
+	else
+	{
+		xchat_printf (ph, " * Client:  XChat-WDK %s (x%d)\n", xchat_get_info (ph, "wdk_version"), getCpuArch ());
+		xchat_printf (ph, " * OS:      %s\n", wmiOs);
+		xchat_printf (ph, " * CPU:     %s (%s)\n", wmiCpu, getCpuMhz ());
+		xchat_printf (ph, " * RAM:     %s\n", getMemoryInfo ());
+		xchat_printf (ph, " * VGA:     %s\n", wmiVga);
+		xchat_printf (ph, " * Uptime:  %.2f Hours\n", (float) GetTickCount() / 1000 / 60 / 60);
+	}
+
+	return XCHAT_EAT_XCHAT;
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	firstRun = 1;
+
+	xchat_hook_command (ph, "WINSYS", XCHAT_PRI_NORM, printInfo, NULL, NULL);
+	xchat_command (ph, "MENU -ietc\\system.png ADD \"Window/Display System Info\" \"WINSYS\"");
+
+	xchat_printf (ph, "%s plugin loaded\n", name);
+
+	return 1;       /* return 1 for success */
+}
+
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_command (ph, "MENU DEL \"Window/Display System Info\"");
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
diff --git a/plugins/wmpa/ReadMe.txt b/plugins/wmpa/ReadMe.txt
new file mode 100644
index 00000000..00a549f8
--- /dev/null
+++ b/plugins/wmpa/ReadMe.txt
@@ -0,0 +1,70 @@
+========================================================================

+       MICROSOFT FOUNDATION CLASS LIBRARY : wmpa

+========================================================================

+

+

+AppWizard has created this wmpa DLL for you.  This DLL not only

+demonstrates the basics of using the Microsoft Foundation classes but

+is also a starting point for writing your DLL.

+

+This file contains a summary of what you will find in each of the files that

+make up your wmpa DLL.

+

+wmpa.dsp

+    This file (the project file) contains information at the project level and

+    is used to build a single project or subproject. Other users can share the

+    project (.dsp) file, but they should export the makefiles locally.

+

+wmpa.h

+	This is the main header file for the DLL.  It declares the

+	CWmpaApp class.

+

+wmpa.cpp

+	This is the main DLL source file.  It contains the class CWmpaApp.

+	It also contains the OLE entry points required of inproc servers.

+

+wmpa.odl

+    This file contains the Object Description Language source code for the

+    type library of your DLL.

+

+wmpa.rc

+    This is a listing of all of the Microsoft Windows resources that the

+    program uses.  It includes the icons, bitmaps, and cursors that are stored

+    in the RES subdirectory.  This file can be directly edited in Microsoft

+	Visual C++.

+

+wmpa.clw

+    This file contains information used by ClassWizard to edit existing

+    classes or add new classes.  ClassWizard also uses this file to store

+    information needed to create and edit message maps and dialog data

+    maps and to create prototype member functions.

+

+res\wmpa.rc2

+    This file contains resources that are not edited by Microsoft 

+	Visual C++.  You should place all resources not editable by

+	the resource editor in this file.

+

+wmpa.def

+    This file contains information about the DLL that must be

+    provided to run with Microsoft Windows.  It defines parameters

+    such as the name and description of the DLL.  It also exports

+	functions from the DLL.

+

+/////////////////////////////////////////////////////////////////////////////

+Other standard files:

+

+StdAfx.h, StdAfx.cpp

+    These files are used to build a precompiled header (PCH) file

+    named wmpa.pch and a precompiled types file named StdAfx.obj.

+

+Resource.h

+    This is the standard header file, which defines new resource IDs.

+    Microsoft Visual C++ reads and updates this file.

+

+/////////////////////////////////////////////////////////////////////////////

+Other notes:

+

+AppWizard uses "TODO:" to indicate parts of the source code you

+should add to or customize.

+

+/////////////////////////////////////////////////////////////////////////////

diff --git a/plugins/wmpa/StdAfx.cpp b/plugins/wmpa/StdAfx.cpp
new file mode 100644
index 00000000..ae3c5313
--- /dev/null
+++ b/plugins/wmpa/StdAfx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes

+//	wmpa.pch will be the pre-compiled header

+//	stdafx.obj will contain the pre-compiled type information

+

+#include "stdafx.h"

+

+

+

diff --git a/plugins/wmpa/StdAfx.h b/plugins/wmpa/StdAfx.h
new file mode 100644
index 00000000..f88a91f3
--- /dev/null
+++ b/plugins/wmpa/StdAfx.h
@@ -0,0 +1,62 @@
+// stdafx.h : include file for standard system include files,

+//  or project specific include files that are used frequently, but

+//      are changed infrequently

+//

+

+#if !defined(AFX_STDAFX_H__33D7BD1A_A9B6_4BDE_B867_5278529B95B2__INCLUDED_)

+#define AFX_STDAFX_H__33D7BD1A_A9B6_4BDE_B867_5278529B95B2__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+

+#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

+

+#include <afxwin.h>         // MFC core and standard components

+#include <afxext.h>         // MFC extensions

+

+#ifndef _AFX_NO_OLE_SUPPORT

+#include <afxole.h>         // MFC OLE classes

+#include <afxodlgs.h>       // MFC OLE dialog classes

+#include <afxdisp.h>        // MFC Automation classes

+#endif // _AFX_NO_OLE_SUPPORT

+

+

+#ifndef _AFX_NO_DB_SUPPORT

+#include <afxdb.h>			// MFC ODBC database classes

+#endif // _AFX_NO_DB_SUPPORT

+

+#ifndef _AFX_NO_DAO_SUPPORT

+#include <afxdao.h>			// MFC DAO database classes

+#endif // _AFX_NO_DAO_SUPPORT

+

+#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls

+#ifndef _AFX_NO_AFXCMN_SUPPORT

+#include <afxcmn.h>			// MFC support for Windows Common Controls

+#endif // _AFX_NO_AFXCMN_SUPPORT

+

+/******************************************************************

+* Includes

+******************************************************************/

+#include "wmpcdrom.h"

+#include "wmpcdromcollection.h"

+#include "wmpclosedcaption.h"

+#include "wmpcontrols.h"

+#include "wmpdvd.h"

+#include "wmperror.h"

+#include "wmperroritem.h"

+#include "wmpmedia.h"

+#include "wmpmediacollection.h"

+#include "wmpnetwork.h"

+#include "wmpplayer4.h"

+#include "wmpplayerapplication.h"

+#include "wmpplaylist.h"

+#include "wmpplaylistarray.h"

+#include "wmpplaylistcollection.h"

+#include "wmpsettings.h"

+#include "wmpstringcollection.h"

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_STDAFX_H__33D7BD1A_A9B6_4BDE_B867_5278529B95B2__INCLUDED_)

diff --git a/plugins/wmpa/makefile.mak b/plugins/wmpa/makefile.mak
new file mode 100644
index 00000000..37e0ecd0
--- /dev/null
+++ b/plugins/wmpa/makefile.mak
@@ -0,0 +1,53 @@
+include "..\..\src\makeinc.mak"
+
+TARGET = xcwmpa.dll
+
+WMPA_OBJECTS = \
+wmpa.obj \
+wmpadialog.obj \
+wmpcdrom.obj \
+wmpcdromcollection.obj \
+wmpclosedcaption.obj \
+wmpcontrols.obj \
+wmpdvd.obj \
+wmperror.obj \
+wmperroritem.obj \
+wmpmedia.obj \
+wmpmediacollection.obj \
+wmpnetwork.obj \
+wmpplayer4.obj \
+wmpplayerapplication.obj \
+wmpplaylist.obj \
+wmpplaylistarray.obj \
+wmpplaylistcollection.obj \
+wmpsettings.obj \
+wmpstringcollection.obj \
+xchat-plugin.obj
+
+CPPFLAGS = $(CPPFLAGS) /EHsc /D_AFXDLL /D_AFX_NO_DAO_SUPPORT /D_WINDLL /D_USRDLL 
+
+all: $(WMPA_OBJECTS) $(TARGET)
+
+.cpp.obj:
+	$(CC) $(CPPFLAGS) /Yc"StdAfx.h" /Fp"wmpa.pch" StdAfx.cpp
+	$(CC) $(CPPFLAGS) /Yu"StdAfx.h" /Fp"wmpa.pch" /c $<
+
+$(TARGET): $(WMPA_OBJECTS)
+	rc /nologo /D_AFXDLL wmpa.rc
+!ifdef X64
+	midl /nologo /mktyplib203 /char signed /env x64 /h wmpa_h.h /tlb wmpa.tlb wmpa.odl
+!else
+	midl /nologo /mktyplib203 /char signed /env win32 /h wmpa_h.h /tlb wmpa.tlb wmpa.odl
+!endif
+	$(LINK) /DLL /out:$(TARGET) $(LDFLAGS) $(WMPA_OBJECTS) $(LIBS) /def:wmpa.def wmpa.res
+
+clean:
+	del $(TARGET)
+	del *.obj
+	del wmpa.pch
+	del wmpa.res
+	del wmpa.tlb
+	del wmpa_h.h
+	del wmpa_i.c
+	del *.exp
+	del *.lib
diff --git a/plugins/wmpa/res/wmpa.rc2 b/plugins/wmpa/res/wmpa.rc2
new file mode 100644
index 00000000..a45caf5c
--- /dev/null
+++ b/plugins/wmpa/res/wmpa.rc2
@@ -0,0 +1,13 @@
+//

+// WMPA.RC2 - resources Microsoft Visual C++ does not edit directly

+//

+

+#ifdef APSTUDIO_INVOKED

+	#error this file is not editable by Microsoft Visual C++

+#endif //APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+// Add manually edited resources here...

+

+/////////////////////////////////////////////////////////////////////////////

diff --git a/plugins/wmpa/resource.h b/plugins/wmpa/resource.h
new file mode 100644
index 00000000..0ce93a4c
--- /dev/null
+++ b/plugins/wmpa/resource.h
@@ -0,0 +1,22 @@
+//{{NO_DEPENDENCIES}}

+// Microsoft Developer Studio generated include file.

+// Used by wmpa.rc

+//

+#define IDD_WMPADIALOG                  2000

+#define IDC_PLAYLIST                    2001

+#define IDC_STATIC1                     2002

+#define IDC_WMP                         2005

+#define IDI_XCHAT                       2005

+#define IDC_SONGLIST                    2006

+#define IDC_STATIC2                     2007

+

+// Next default values for new objects

+// 

+#ifdef APSTUDIO_INVOKED

+#ifndef APSTUDIO_READONLY_SYMBOLS

+#define _APS_NEXT_RESOURCE_VALUE        2006

+#define _APS_NEXT_COMMAND_VALUE         32771

+#define _APS_NEXT_CONTROL_VALUE         2008

+#define _APS_NEXT_SYMED_VALUE           2000

+#endif

+#endif

diff --git a/plugins/wmpa/wmpa.cpp b/plugins/wmpa/wmpa.cpp
new file mode 100644
index 00000000..d9488f6d
--- /dev/null
+++ b/plugins/wmpa/wmpa.cpp
@@ -0,0 +1,212 @@
+/******************************************************************

+* $Id$

+*

+* $Log$

+*

+* Copyright © 2005 David Cullen, All rights reserved

+*

+******************************************************************/

+#include "stdafx.h"

+#include "wmpa.h"

+#include "WMPADialog.h"

+

+#ifdef _DEBUG

+#define new DEBUG_NEW

+#undef THIS_FILE

+static char THIS_FILE[] = __FILE__;

+#endif

+

+//

+//	Note!

+//

+//		If this DLL is dynamically linked against the MFC

+//		DLLs, any functions exported from this DLL which

+//		call into MFC must have the AFX_MANAGE_STATE macro

+//		added at the very beginning of the function.

+//

+//		For example:

+//

+//		extern "C" BOOL PASCAL EXPORT ExportedFunction()

+//		{

+//			AFX_MANAGE_STATE(AfxGetStaticModuleState());

+//			// normal function body here

+//		}

+//

+//		It is very important that this macro appear in each

+//		function, prior to any calls into MFC.  This means that

+//		it must appear as the first statement within the

+//		function, even before any object variable declarations

+//		as their constructors may generate calls into the MFC

+//		DLL.

+//

+//		Please see MFC Technical Notes 33 and 58 for additional

+//		details.

+//

+

+/////////////////////////////////////////////////////////////////////////////

+// CWmpaApp

+

+BEGIN_MESSAGE_MAP(CWmpaApp, CWinApp)

+	//{{AFX_MSG_MAP(CWmpaApp)

+		// NOTE - the ClassWizard will add and remove mapping macros here.

+		//    DO NOT EDIT what you see in these blocks of generated code!

+	//}}AFX_MSG_MAP

+END_MESSAGE_MAP()

+

+/////////////////////////////////////////////////////////////////////////////

+// CWmpaApp construction

+

+CWmpaApp::CWmpaApp()

+{

+	// TODO: add construction code here,

+	// Place all significant initialization in InitInstance

+   m_pDialog = NULL;

+}

+

+/////////////////////////////////////////////////////////////////////////////

+// The one and only CWmpaApp object

+

+CWmpaApp theApp;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWmpaApp initialization

+

+BOOL CWmpaApp::InitInstance()

+{

+	// Register all OLE server (factories) as running.  This enables the

+	//  OLE libraries to create objects from other applications.

+	COleObjectFactory::RegisterAll();

+

+   // WARNING: This function enables the ActiveX control container

+   // Without this function you will not be able to load the WMP

+   // In fact you will get the following error:

+   // >>> If this dialog has OLE controls:

+   // >>> AfxEnableControlContainer has not been called yet.

+   // >>> You should call it in your app's InitInstance function.

+   AfxEnableControlContainer();

+

+   // WARNING: This function initializes the COM library for use

+   // Without this function you will not be able to load the WMP

+   // In fact you will get the following error:

+   // CoCreateInstance of OLE control {6BF52A52-394A-11D3-B153-00C04F79FAA6} failed.

+   // >>> Result code: 0x800401f0

+   // >>> Is the control is properly registered?

+   // The Error Lookup tool will tell you result code 0x800401F0 means

+   // CoInitialize has not been called.

+   CoInitialize(NULL);

+

+   return TRUE;

+}

+

+/******************************************************************

+* ShowWMPA

+******************************************************************/

+BOOL CWmpaApp::ShowWMPA(void)

+{

+   HRESULT result = FALSE;

+   BOOL created;

+

+   // WARNING: The following two funcions make sure we look for

+   // our resources in our DLL not in the calling EXE

+   // Without these functions you will not be able to load the

+   // Windows Media Player

+   HMODULE hModule = GetModuleHandle("WMPA.DLL");

+   AfxSetResourceHandle((HINSTANCE) hModule);

+

+   if (m_pDialog == NULL) m_pDialog = new CWMPADialog;

+

+   created = m_pDialog->Create(IDD_WMPADIALOG, m_pDialog);

+   if (!created) return(E_FAIL);

+   m_pDialog->m_hIcon = LoadIcon(IDI_XCHAT);

+   m_pDialog->SetIcon(m_pDialog->m_hIcon, TRUE);

+

+   result = m_pDialog->ShowWindow(SW_SHOWNORMAL);

+

+   return(created);

+}

+

+/////////////////////////////////////////////////////////////////////////////

+// Special entry points required for inproc servers

+

+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+	return AfxDllGetClassObject(rclsid, riid, ppv);

+}

+

+STDAPI DllCanUnloadNow(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+	return AfxDllCanUnloadNow();

+}

+

+// by exporting DllRegisterServer, you can use regsvr.exe

+STDAPI DllRegisterServer(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+	COleObjectFactory::UpdateRegistryAll();

+   return(S_OK);

+}

+

+/******************************************************************

+* DestroyWMPA

+******************************************************************/

+BOOL CWmpaApp::DestroyWMPA(void)

+{

+   if (theApp.m_pDialog == NULL) return(FALSE);

+

+   theApp.m_pDialog->m_WMP.GetControls().stop();

+   theApp.m_pDialog->DeleteTrayIcon();

+   theApp.m_pDialog->DestroyWindow();

+

+   return(TRUE);

+}

+

+/******************************************************************

+* StartWindowsMediaPlayer

+******************************************************************/

+BOOL StartWindowsMediaPlayer(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+

+   BOOL result = theApp.ShowWMPA();

+

+   return(result);

+}

+

+/******************************************************************

+* StopWindowsMediaPlayer

+******************************************************************/

+BOOL StopWindowsMediaPlayer(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+

+   BOOL result = theApp.DestroyWMPA();

+

+   return(result);

+}

+

+/******************************************************************

+* GetWindowsMediaPlayer

+******************************************************************/

+CWMPPlayer4 *GetWindowsMediaPlayer(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+

+   if (theApp.m_pDialog == NULL) return(NULL);

+

+	return(&(theApp.m_pDialog->m_WMP));

+}

+

+/******************************************************************

+* GetWMPADialog

+******************************************************************/

+CWMPADialog *GetWMPADialog(void)

+{

+	AFX_MANAGE_STATE(AfxGetStaticModuleState());

+

+   if (theApp.m_pDialog == NULL) return(NULL);

+

+	return(theApp.m_pDialog);

+}

+

diff --git a/plugins/wmpa/wmpa.def b/plugins/wmpa/wmpa.def
new file mode 100644
index 00000000..3555558e
--- /dev/null
+++ b/plugins/wmpa/wmpa.def
@@ -0,0 +1,15 @@
+; wmpa.def : Declares the module parameters for the DLL.

+

+LIBRARY      "xcwmpa"

+

+EXPORTS

+    ; Explicit exports can go here

+    DllCanUnloadNow PRIVATE

+    DllGetClassObject PRIVATE

+    DllRegisterServer PRIVATE

+    xchat_plugin_init

+    xchat_plugin_deinit

+    xchat_plugin_get_info

+    StartWindowsMediaPlayer

+    GetWindowsMediaPlayer

+    GetWMPADialog

diff --git a/plugins/wmpa/wmpa.h b/plugins/wmpa/wmpa.h
new file mode 100644
index 00000000..39961835
--- /dev/null
+++ b/plugins/wmpa/wmpa.h
@@ -0,0 +1,61 @@
+/******************************************************************

+* $Id$

+*

+* $Log$

+*

+* Copyright © 2005 David Cullen, All rights reserved

+*

+******************************************************************/

+#if !defined(AFX_WMPA_H__11200FE3_F137_48DD_8020_91CF7BBB283B__INCLUDED_)

+#define AFX_WMPA_H__11200FE3_F137_48DD_8020_91CF7BBB283B__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+

+#ifndef __AFXWIN_H__

+	#error include 'stdafx.h' before including this file for PCH

+#endif

+

+#include "resource.h"		// main symbols

+#include "WMPADialog.h"

+

+/////////////////////////////////////////////////////////////////////////////

+// CWmpaApp

+// See wmpa.cpp for the implementation of this class

+//

+

+class CWmpaApp : public CWinApp

+{

+public:

+	CWmpaApp();

+

+   BOOL ShowWMPA(void);

+   BOOL DestroyWMPA(void);

+

+   CWMPADialog *m_pDialog;

+// Overrides

+	// ClassWizard generated virtual function overrides

+	//{{AFX_VIRTUAL(CWmpaApp)

+	public:

+	virtual BOOL InitInstance();

+	//}}AFX_VIRTUAL

+

+	//{{AFX_MSG(CWmpaApp)

+		// NOTE - the ClassWizard will add and remove member functions here.

+		//    DO NOT EDIT what you see in these blocks of generated code !

+	//}}AFX_MSG

+	DECLARE_MESSAGE_MAP()

+};

+

+BOOL StartWindowsMediaPlayer(void);

+BOOL StopWindowsMediaPlayer(void);

+CWMPPlayer4 *GetWindowsMediaPlayer(void);

+CWMPADialog *GetWMPADialog(void);

+

+/////////////////////////////////////////////////////////////////////////////

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPA_H__11200FE3_F137_48DD_8020_91CF7BBB283B__INCLUDED_)

diff --git a/plugins/wmpa/wmpa.ico b/plugins/wmpa/wmpa.ico
new file mode 100644
index 00000000..fb68714c
--- /dev/null
+++ b/plugins/wmpa/wmpa.ico
Binary files differdiff --git a/plugins/wmpa/wmpa.odl b/plugins/wmpa/wmpa.odl
new file mode 100644
index 00000000..1c354c34
--- /dev/null
+++ b/plugins/wmpa/wmpa.odl
@@ -0,0 +1,44 @@
+// wmpa.odl : type library source for wmpa.dll

+

+// This file will be processed by the MIDL compiler to produce the

+// type library (wmpa.tlb).

+

+[ uuid(2D225385-EFD3-4DD8-9377-A7F244C522D0), version(1.0) ]

+library Wmpa

+{

+	importlib("stdole32.tlb");

+	importlib("stdole2.tlb");

+

+

+

+

+	//  Primary dispatch interface for CWMPADIALOG

+	

+	[ uuid(01C1B3AA-C7FC-4023-89A5-C814E1B62B9B) ]

+	dispinterface IWMPADIALOG

+	{

+		properties:

+			// NOTE - ClassWizard will maintain property information here.

+			//    Use extreme caution when editing this section.

+			//{{AFX_ODL_PROP(CWMPADIALOG)

+			//}}AFX_ODL_PROP

+			

+		methods:

+			// NOTE - ClassWizard will maintain method information here.

+			//    Use extreme caution when editing this section.

+			//{{AFX_ODL_METHOD(CWMPADIALOG)

+			//}}AFX_ODL_METHOD

+

+	};

+

+	//  Class information for CWMPADIALOG

+

+	[ uuid(9007B1B4-0006-453D-A799-DB8CBA1AE22A) ]

+	coclass WMPADIALOG

+	{

+		[default] dispinterface IWMPADIALOG;

+	};

+

+	//{{AFX_APPEND_ODL}}

+	//}}AFX_APPEND_ODL}}

+};

diff --git a/plugins/wmpa/wmpa.rc b/plugins/wmpa/wmpa.rc
new file mode 100644
index 00000000..b99b4bfb
--- /dev/null
+++ b/plugins/wmpa/wmpa.rc
@@ -0,0 +1,207 @@
+//Microsoft Developer Studio generated resource script.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#include "afxres.h"

+

+/////////////////////////////////////////////////////////////////////////////

+#undef APSTUDIO_READONLY_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+// English (U.S.) resources

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

+#pragma code_page(1252)

+#endif //_WIN32

+

+#ifdef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// TEXTINCLUDE

+//

+

+1 TEXTINCLUDE DISCARDABLE 

+BEGIN

+    "resource.h\0"

+END

+

+2 TEXTINCLUDE DISCARDABLE 

+BEGIN

+    "#include ""afxres.h""\r\n"

+    "\0"

+END

+

+3 TEXTINCLUDE DISCARDABLE 

+BEGIN

+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"

+    "#define _AFX_NO_OLE_RESOURCES\r\n"

+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"

+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"

+    "\r\n"

+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"

+    "#ifdef _WIN32\r\n"

+    "LANGUAGE 9, 1\r\n"

+    "#pragma code_page(1252)\r\n"

+    "#endif //_WIN32\r\n"

+    "#include ""res\\wmpa.rc2""  // non-Microsoft Visual C++ edited resources\r\n"

+    "#include ""afxres.rc""         // Standard components\r\n"

+    "#endif\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+

+#ifndef _MAC

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION 1,0,0,1

+ PRODUCTVERSION 1,0,0,1

+ FILEFLAGSMASK 0x3fL

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x4L

+ FILETYPE 0x2L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904B0"

+        BEGIN

+            VALUE "CompanyName", "\0"

+            VALUE "FileDescription", "wmpa DLL\0"

+            VALUE "FileVersion", "1, 0, 0, 1\0"

+            VALUE "InternalName", "wmpa\0"

+            VALUE "LegalCopyright", "Copyright (C) 2005\0"

+            VALUE "LegalTrademarks", "\0"

+            VALUE "OriginalFilename", "wmpa.DLL\0"

+            VALUE "ProductName", "wmpa Dynamic Link Library\0"

+            VALUE "ProductVersion", "1, 0, 0, 1\0"

+            VALUE "OLESelfRegister", "\0"

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1200

+    END

+END

+

+#endif    // !_MAC

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Dialog

+//

+

+IDD_WMPADIALOG DIALOG DISCARDABLE  0, 0, 317, 236

+STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU

+CAPTION "Unitialized"

+FONT 8, "MS Sans Serif"

+BEGIN

+    LISTBOX         IDC_PLAYLIST,165,15,145,145,LBS_NOINTEGRALHEIGHT | 

+                    WS_VSCROLL | WS_HSCROLL | WS_TABSTOP

+    LTEXT           "Play Lists (Double-click to play)",IDC_STATIC1,165,5,

+                    145,10

+    CONTROL         "",IDC_WMP,"{6BF52A52-394A-11D3-B153-00C04F79FAA6}",

+                    WS_TABSTOP,5,5,155,155

+    LISTBOX         IDC_SONGLIST,5,175,305,55,LBS_NOINTEGRALHEIGHT | 

+                    WS_VSCROLL | WS_TABSTOP

+    LTEXT           "Song List (Double-click to play)",IDC_STATIC2,5,165,305,

+                    10

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// DESIGNINFO

+//

+

+#ifdef APSTUDIO_INVOKED

+GUIDELINES DESIGNINFO DISCARDABLE 

+BEGIN

+    IDD_WMPADIALOG, DIALOG

+    BEGIN

+        LEFTMARGIN, 7

+        RIGHTMARGIN, 310

+        TOPMARGIN, 7

+        BOTTOMMARGIN, 229

+    END

+END

+#endif    // APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Dialog Info

+//

+

+IDD_WMPADIALOG DLGINIT

+BEGIN

+    IDC_WMP, 0x376, 166, 0

+0x0000, 0x0000, 0x0300, 0x0000, 0x0008, 0x0000, 0x0000, 0x0005, 0x0000, 

+0x0000, 0x0000, 0x3ff0, 0x0003, 0x0000, 0x0000, 0x0005, 0x0000, 0x0000, 

+0x0000, 0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 0x0003, 0x0001, 0x0000, 

+0x000b, 0xffff, 0x0003, 0x0000, 0x0000, 0x000b, 0xffff, 0x0008, 0x0002, 

+0x0000, 0x0000, 0x0003, 0x0032, 0x0000, 0x000b, 0x0000, 0x0008, 0x000a, 

+0x0000, 0x0066, 0x0075, 0x006c, 0x006c, 0x0000, 0x000b, 0x0000, 0x000b, 

+0x0000, 0x000b, 0xffff, 0x000b, 0xffff, 0x000b, 0x0000, 0x0008, 0x0002, 

+0x0000, 0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 0x0008, 0x0002, 0x0000, 

+0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 0x000b, 0x0000, 0x1815, 0x0000, 

+0x1a0c, 0x0000, 

+    0

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Icon

+//

+

+// Icon with lowest ID value placed first to ensure application icon

+// remains consistent on all systems.

+//

+// the WMP icon comes from here:

+// http://www.iconarchive.com/show/phuzion-icons-by-kyo-tux/Applic-WMP-icon.html

+IDI_XCHAT               ICON    DISCARDABLE     "wmpa.ico"

+#endif    // English (U.S.) resources

+/////////////////////////////////////////////////////////////////////////////

+

+

+

+#ifndef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+#define _AFX_NO_SPLITTER_RESOURCES

+#define _AFX_NO_OLE_RESOURCES

+#define _AFX_NO_TRACKER_RESOURCES

+#define _AFX_NO_PROPERTY_RESOURCES

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE 9, 1

+#pragma code_page(1252)

+#endif //_WIN32

+#include "res\wmpa.rc2"  // non-Microsoft Visual C++ edited resources

+#include "afxres.rc"         // Standard components

+#endif

+

+/////////////////////////////////////////////////////////////////////////////

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/plugins/wmpa/wmpa.sln b/plugins/wmpa/wmpa.sln
new file mode 100644
index 00000000..a3b71091
--- /dev/null
+++ b/plugins/wmpa/wmpa.sln
@@ -0,0 +1,20 @@
+

+Microsoft Visual Studio Solution File, Format Version 11.00

+# Visual Studio 2010

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wmpa", "wmpa.vcxproj", "{08AD7C4D-DDDC-9545-A8D7-1808E6056143}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Release|Win32 = Release|Win32

+		Release|x64 = Release|x64

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{08AD7C4D-DDDC-9545-A8D7-1808E6056143}.Release|Win32.ActiveCfg = Release|Win32

+		{08AD7C4D-DDDC-9545-A8D7-1808E6056143}.Release|Win32.Build.0 = Release|Win32

+		{08AD7C4D-DDDC-9545-A8D7-1808E6056143}.Release|x64.ActiveCfg = Release|x64

+		{08AD7C4D-DDDC-9545-A8D7-1808E6056143}.Release|x64.Build.0 = Release|x64

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/plugins/wmpa/wmpa.vcxproj b/plugins/wmpa/wmpa.vcxproj
new file mode 100644
index 00000000..919c2c00
--- /dev/null
+++ b/plugins/wmpa/wmpa.vcxproj
@@ -0,0 +1,231 @@
+<?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>

+  <PropertyGroup Label="Globals">

+    <SccProjectName />

+    <SccLocalPath />

+    <Keyword>MFCProj</Keyword>

+  </PropertyGroup>

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

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

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <UseOfMfc>Dynamic</UseOfMfc>

+    <CharacterSet>MultiByte</CharacterSet>

+  </PropertyGroup>

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

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <UseOfMfc>Dynamic</UseOfMfc>

+    <CharacterSet>MultiByte</CharacterSet>

+  </PropertyGroup>

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

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

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

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

+    <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.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="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

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

+    <OutDir>.\Release\</OutDir>

+    <IntDir>.\Release\</IntDir>

+    <LinkIncremental>false</LinkIncremental>

+    <TargetName>xcwmpa</TargetName>

+  </PropertyGroup>

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

+    <OutDir>.\Release\</OutDir>

+    <IntDir>.\Release\</IntDir>

+    <LinkIncremental>false</LinkIncremental>

+    <TargetName>xcwmpa</TargetName>

+  </PropertyGroup>

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

+    <ClCompile>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>

+      <StringPooling>true</StringPooling>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <Optimization>MaxSpeed</Optimization>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <WarningLevel>Level3</WarningLevel>

+      <AdditionalIncludeDirectories>c:\WinDDK\7600.16385.1\inc\api;c:\WinDDK\7600.16385.1\inc\crt;c:\WinDDK\7600.16385.1\inc\mfc42;c:\WinDDK\7600.16385.1\inc\ddk;c:\WinDDK\7600.16385.1\inc\api\dao360</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WINDLL;_USRDLL;_AFXDLL;_AFX_NO_DAO_SUPPORT</PreprocessorDefinitions>

+      <AssemblerListingLocation>.\Release\</AssemblerListingLocation>

+      <PrecompiledHeaderOutputFile>.\Release\wmpa.pch</PrecompiledHeaderOutputFile>

+      <PrecompiledHeader>Use</PrecompiledHeader>

+      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>

+      <ObjectFileName>.\Release\</ObjectFileName>

+      <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName>

+    </ClCompile>

+    <Midl>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <TypeLibraryName>.\Release\wmpa.tlb</TypeLibraryName>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <TargetEnvironment>Win32</TargetEnvironment>

+    </Midl>

+    <ResourceCompile>

+      <Culture>0x0409</Culture>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+    </ResourceCompile>

+    <Bscmake>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <OutputFile>.\Release\wmpa.bsc</OutputFile>

+    </Bscmake>

+    <Link>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <LinkDLL>true</LinkDLL>

+      <SubSystem>Windows</SubSystem>

+      <OutputFile>.\Release\xcwmpa.dll</OutputFile>

+      <ImportLibrary>.\Release\wmpa.lib</ImportLibrary>

+      <ModuleDefinitionFile>.\wmpa.def</ModuleDefinitionFile>

+      <AdditionalLibraryDirectories>c:\WinDDK\7600.16385.1\lib\Crt\i386;c:\WinDDK\7600.16385.1\lib\wxp\i386;c:\WinDDK\7600.16385.1\lib\Mfc\i386;c:\WinDDK\7600.16385.1\lib\ATL\i386</AdditionalLibraryDirectories>

+      <AdditionalDependencies>msvcrt_winxp.obj</AdditionalDependencies>

+    </Link>

+    <CustomBuildStep>

+      <Command>

+      </Command>

+      <Outputs>

+      </Outputs>

+      <Message>

+      </Message>

+    </CustomBuildStep>

+  </ItemDefinitionGroup>

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

+    <ClCompile>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>

+      <StringPooling>true</StringPooling>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <Optimization>MaxSpeed</Optimization>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <WarningLevel>Level3</WarningLevel>

+      <AdditionalIncludeDirectories>c:\WinDDK\7600.16385.1\inc\api;c:\WinDDK\7600.16385.1\inc\crt;c:\WinDDK\7600.16385.1\inc\mfc42;c:\WinDDK\7600.16385.1\inc\ddk;c:\WinDDK\7600.16385.1\inc\api\dao360</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_WINDLL;_USRDLL;_AFXDLL;_AFX_NO_DAO_SUPPORT</PreprocessorDefinitions>

+      <AssemblerListingLocation>.\Release\</AssemblerListingLocation>

+      <PrecompiledHeaderOutputFile>.\Release\wmpa.pch</PrecompiledHeaderOutputFile>

+      <PrecompiledHeader>Use</PrecompiledHeader>

+      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>

+      <ObjectFileName>.\Release\</ObjectFileName>

+      <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName>

+    </ClCompile>

+    <Midl>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <TypeLibraryName>.\Release\wmpa.tlb</TypeLibraryName>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <TargetEnvironment>X64</TargetEnvironment>

+    </Midl>

+    <ResourceCompile>

+      <Culture>0x0409</Culture>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+    </ResourceCompile>

+    <Bscmake>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <OutputFile>.\Release\wmpa.bsc</OutputFile>

+    </Bscmake>

+    <Link>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <LinkDLL>true</LinkDLL>

+      <SubSystem>Windows</SubSystem>

+      <OutputFile>.\Release\xcwmpa.dll</OutputFile>

+      <ImportLibrary>.\Release\wmpa.lib</ImportLibrary>

+      <ModuleDefinitionFile>.\wmpa.def</ModuleDefinitionFile>

+      <AdditionalLibraryDirectories>c:\WinDDK\7600.16385.1\lib\Crt\amd64;c:\WinDDK\7600.16385.1\lib\wnet\amd64;c:\WinDDK\7600.16385.1\lib\Mfc\amd64;c:\WinDDK\7600.16385.1\lib\ATL\amd64</AdditionalLibraryDirectories>

+      <AdditionalDependencies>msvcrt_win2003.obj</AdditionalDependencies>

+    </Link>

+    <CustomBuildStep>

+      <Command>

+      </Command>

+      <Outputs>

+      </Outputs>

+      <Message>

+      </Message>

+    </CustomBuildStep>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="StdAfx.cpp">

+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>

+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdafx.h</PrecompiledHeaderFile>

+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdafx.h</PrecompiledHeaderFile>

+    </ClCompile>

+    <ClCompile Include="wmpa.cpp" />

+    <ClCompile Include="WMPADialog.cpp" />

+    <ClCompile Include="wmpcdrom.cpp" />

+    <ClCompile Include="wmpcdromcollection.cpp" />

+    <ClCompile Include="wmpclosedcaption.cpp" />

+    <ClCompile Include="wmpcontrols.cpp" />

+    <ClCompile Include="wmpdvd.cpp" />

+    <ClCompile Include="wmperror.cpp" />

+    <ClCompile Include="wmperroritem.cpp" />

+    <ClCompile Include="wmpmedia.cpp" />

+    <ClCompile Include="wmpmediacollection.cpp" />

+    <ClCompile Include="wmpnetwork.cpp" />

+    <ClCompile Include="wmpplayer4.cpp" />

+    <ClCompile Include="wmpplayerapplication.cpp" />

+    <ClCompile Include="wmpplaylist.cpp" />

+    <ClCompile Include="wmpplaylistarray.cpp" />

+    <ClCompile Include="wmpplaylistcollection.cpp" />

+    <ClCompile Include="wmpsettings.cpp" />

+    <ClCompile Include="wmpstringcollection.cpp" />

+    <ClCompile Include="xchat-plugin.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="wmpa.def" />

+    <CustomBuild Include="res\wmpa.rc2">

+      <FileType>RC</FileType>

+    </CustomBuild>

+    <CustomBuild Include="wmpa.ico" />

+    <CustomBuild Include="ReadMe.txt" />

+  </ItemGroup>

+  <ItemGroup>

+    <Midl Include="wmpa.odl">

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

+    </Midl>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="wmpa.rc">

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OUTDIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OUTDIR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+  </ItemGroup>

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

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/plugins/wmpa/wmpa.vcxproj.filters b/plugins/wmpa/wmpa.vcxproj.filters
new file mode 100644
index 00000000..6962f46e
--- /dev/null
+++ b/plugins/wmpa/wmpa.vcxproj.filters
@@ -0,0 +1,172 @@
+<?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>{3206fd00-efdb-4bca-9740-9708bd405701}</UniqueIdentifier>

+      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{17e13eb2-1243-4ff2-9532-1d6dab0bfef9}</UniqueIdentifier>

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

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{a1d9cf8c-f0bb-4a19-bfff-5223276e650a}</UniqueIdentifier>

+      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="StdAfx.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpa.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="WMPADialog.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpcdrom.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpcdromcollection.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpclosedcaption.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpcontrols.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpdvd.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmperror.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmperroritem.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpmedia.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpmediacollection.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpnetwork.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpplayer4.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpplayerapplication.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpplaylist.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpplaylistarray.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpplaylistcollection.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpsettings.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="wmpstringcollection.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="xchat-plugin.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <Midl Include="wmpa.odl">

+      <Filter>Source Files</Filter>

+    </Midl>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="wmpa.rc">

+      <Filter>Source Files</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="Resource.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="StdAfx.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpa.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="WMPADIALOG.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpcdrom.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpcdromcollection.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpclosedcaption.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpcontrols.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpdvd.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmperror.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmperroritem.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpmedia.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpmediacollection.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpnetwork.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpplayer4.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpplayerapplication.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpplaylist.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpplaylistarray.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpplaylistcollection.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpsettings.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="wmpstringcollection.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

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

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="wmpa.def">

+      <Filter>Source Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="res\wmpa.rc2">

+      <Filter>Resource Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="wmpa.ico">

+      <Filter>Resource Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="ReadMe.txt" />

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/plugins/wmpa/wmpadialog.cpp b/plugins/wmpa/wmpadialog.cpp
new file mode 100644
index 00000000..b0cdd16e
--- /dev/null
+++ b/plugins/wmpa/wmpadialog.cpp
@@ -0,0 +1,375 @@
+/******************************************************************

+* $Id$

+*

+* $Log$

+*

+* Copyright © 2005 David Cullen, All rights reserved

+*

+******************************************************************/

+#include "stdafx.h"

+#include "wmpa.h"

+#include "WMPADialog.h"

+#include "shellapi.h"

+#include "xchat-plugin.h"

+

+#ifdef _DEBUG

+#define new DEBUG_NEW

+#undef THIS_FILE

+static char THIS_FILE[] = __FILE__;

+#endif

+

+#define ID_TRAY_ICON    1000

+#define WM_TRAY_ICON    (WM_APP + 1)

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPADialog dialog

+

+CWMPADialog::CWMPADialog(CWnd* pParent /*=NULL*/)

+	: CDialog(CWMPADialog::IDD, pParent)

+{

+	EnableAutomation();

+

+	//{{AFX_DATA_INIT(CWMPADialog)

+	//}}AFX_DATA_INIT

+}

+

+

+void CWMPADialog::OnFinalRelease()

+{

+	// When the last reference for an automation object is released

+	// OnFinalRelease is called.  The base class will automatically

+	// deletes the object.  Add additional cleanup required for your

+	// object before calling the base class.

+

+	CDialog::OnFinalRelease();

+}

+

+void CWMPADialog::DoDataExchange(CDataExchange* pDX)

+{

+	CDialog::DoDataExchange(pDX);

+	//{{AFX_DATA_MAP(CWMPADialog)

+	DDX_Control(pDX, IDC_SONGLIST, m_SongListBox);

+	DDX_Control(pDX, IDC_PLAYLIST, m_PlaylistBox);

+	DDX_Control(pDX, IDC_WMP, m_WMP);

+	//}}AFX_DATA_MAP

+}

+

+

+BEGIN_MESSAGE_MAP(CWMPADialog, CDialog)

+	//{{AFX_MSG_MAP(CWMPADialog)

+	ON_LBN_DBLCLK(IDC_PLAYLIST, OnDblclkPlaylist)

+	ON_WM_SHOWWINDOW()

+	ON_WM_CLOSE()

+	ON_LBN_DBLCLK(IDC_SONGLIST, OnDblclkSonglist)

+	ON_WM_DESTROY()

+	ON_WM_SIZE()

+	//}}AFX_MSG_MAP

+END_MESSAGE_MAP()

+

+BEGIN_DISPATCH_MAP(CWMPADialog, CDialog)

+	//{{AFX_DISPATCH_MAP(CWMPADialog)

+		// NOTE - the ClassWizard will add and remove mapping macros here.

+	//}}AFX_DISPATCH_MAP

+END_DISPATCH_MAP()

+

+// Note: we add support for IID_IWMPADialog to support typesafe binding

+//  from VBA.  This IID must match the GUID that is attached to the

+//  dispinterface in the .ODL file.

+

+// {01C1B3AA-C7FC-4023-89A5-C814E1B62B9B}

+static const IID IID_IWMPADialog =

+{ 0x1c1b3aa, 0xc7fc, 0x4023, { 0x89, 0xa5, 0xc8, 0x14, 0xe1, 0xb6, 0x2b, 0x9b } };

+

+BEGIN_INTERFACE_MAP(CWMPADialog, CDialog)

+	INTERFACE_PART(CWMPADialog, IID_IWMPADialog, Dispatch)

+END_INTERFACE_MAP()

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPADialog message handlers

+

+void CWMPADialog::OnDblclkPlaylist()

+{

+	// TODO: Add your control notification handler code here

+   long index;

+

+   // Get the playlist name

+   index = m_PlaylistBox.GetCurSel();

+   CString playlistName;

+   m_PlaylistBox.GetText(index, playlistName);

+

+   // Get the playlist

+   CWMPPlaylistCollection pc = m_WMP.GetPlaylistCollection();

+   CWMPPlaylistArray pa = pc.getByName((LPCTSTR) playlistName);

+   CWMPPlaylist playlist = pa.Item(0);

+   m_WMP.SetCurrentPlaylist(playlist);

+

+   // Set the song list

+   UpdateSongList();

+

+   m_WMP.GetControls().play();

+   if (autoAnnounce) {

+      xchat_commandf(ph, "me is playing %s", (LPCTSTR) wmpaGetSongTitle());

+   }

+   else {

+      xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());

+   }

+}

+

+void CWMPADialog::OnShowWindow(BOOL bShow, UINT nStatus)

+{

+	CDialog::OnShowWindow(bShow, nStatus);

+	

+	// TODO: Add your message handler code here

+   if (bShow) {

+      if (!trayInit) {

+         ZeroMemory(&nid, sizeof(nid));

+         nid.cbSize = sizeof(nid);

+         nid.hWnd = m_hWnd;

+         nid.uID = ID_TRAY_ICON;

+         nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;

+         nid.uCallbackMessage = WM_TRAY_ICON;

+         nid.hIcon = m_hIcon;

+         strcpy(nid.szTip, "WMPA");

+         strcat(nid.szTip,  VER_STRING);

+         strcat(nid.szTip, "\nWindows Media\nPlayer Announcer");

+         nid.dwState = 0;

+         nid.dwStateMask = 0;

+         strcpy(nid.szInfo, "WMPA ");

+         strcat(nid.szInfo, VER_STRING);

+         nid.uTimeout = 10000; // 10 second time out

+         strcat(nid.szInfoTitle, "WMPA");

+         nid.dwInfoFlags = 0;

+         trayInit = TRUE;

+      }

+   }

+

+}

+

+

+void CWMPADialog::PostNcDestroy()

+{

+	// TODO: Add your specialized code here and/or call the base class

+   delete this;

+

+	CDialog::PostNcDestroy();

+}

+

+

+BOOL CWMPADialog::OnInitDialog()

+{

+	CDialog::OnInitDialog();

+

+   CString title = "WMPA";

+   title += " ";

+   title += VER_STRING;

+   SetWindowText((LPCTSTR) title);

+

+   UpdatePlayLists();

+

+   autoAnnounce = FALSE;

+   trayInit = FALSE;

+   trayClicked = FALSE;

+

+	return TRUE;  // return TRUE unless you set the focus to a control

+	              // EXCEPTION: OCX Property Pages should return FALSE

+}

+

+void CWMPADialog::OnClose()

+{

+	// TODO: Add your message handler code here and/or call default

+   Shell_NotifyIcon(NIM_ADD, &nid);

+   ShowWindow(SW_HIDE);

+

+   // Don't let the user close the dialog

+//   CDialog::OnClose();

+}

+

+void CWMPADialog::OnCancel()

+{

+//   this->DestroyWindow();

+}

+

+void CWMPADialog::OnDblclkSonglist()

+{

+	// TODO: Add your control notification handler code here

+   int index = m_SongListBox.GetCurSel();

+   m_WMP.GetControls().playItem(m_WMP.GetCurrentPlaylist().GetItem(index));

+   if (autoAnnounce) {

+      xchat_commandf(ph, "me is playing %s", (LPCTSTR) wmpaGetSongTitle());

+   }

+   else {

+      xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());

+   }

+}

+

+BEGIN_EVENTSINK_MAP(CWMPADialog, CDialog)

+    //{{AFX_EVENTSINK_MAP(CWMPADialog)

+	ON_EVENT(CWMPADialog, IDC_WMP, 5806 /* CurrentItemChange */, OnCurrentItemChangeWmp, VTS_DISPATCH)

+	ON_EVENT(CWMPADialog, IDC_WMP, 5101 /* PlayStateChange */, OnPlayStateChangeWmp, VTS_I4)

+	//}}AFX_EVENTSINK_MAP

+END_EVENTSINK_MAP()

+

+void CWMPADialog::OnCurrentItemChangeWmp(LPDISPATCH pdispMedia)

+{

+	// TODO: Add your control notification handler code here

+

+   int state = m_WMP.GetPlayState();

+   if (state == 3) { // Playing

+      if (autoAnnounce) {

+         xchat_commandf(ph, "me is playing %s", (LPCTSTR) wmpaGetSongTitle());

+      }

+      else {

+         xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());

+      }

+   }

+

+   SelectCurrentSong();

+}

+

+void CWMPADialog::OnDestroy()

+{

+	CDialog::OnDestroy();

+	

+   // TODO: Add your message handler code here

+}

+

+void CWMPADialog::UpdateSongList()

+{

+   char buffer[32];

+   CString name;

+   CString artist;

+   CString title;

+   CString album;

+   CString bitrate;

+   CString duration;

+   CString song;

+   long index;

+   long count;

+

+   m_SongListBox.ResetContent();

+   CWMPPlaylist playlist = m_WMP.GetCurrentPlaylist();

+   count = playlist.GetCount();

+   m_SongListBox.ResetContent();

+   for (index = 0; index < count; index++) {

+      name         = playlist.GetItem(index).GetName();

+      artist       = playlist.GetItem(index).getItemInfo("Artist");

+      title        = playlist.GetItem(index).getItemInfo("Title");

+      album        = playlist.GetItem(index).getItemInfo("Album");

+      bitrate      = playlist.GetItem(index).getItemInfo("Bitrate");

+      duration     = playlist.GetItem(index).GetDurationString();

+

+      long krate = strtoul((LPCTSTR) bitrate, NULL, 10) / 1000;

+      _ultoa(krate, buffer, 10);

+      bitrate = CString(buffer);

+

+      if (album.IsEmpty()) {

+         playlist.removeItem(playlist.GetItem(index));

+         count = playlist.GetCount();

+      }

+      else {

+         song = "";

+         song += artist;

+         if (song.IsEmpty()) song = "Various";

+         song += " - ";

+         song += title;

+         song += " (";

+         song += album;

+         song += ") [";

+         song += duration;

+         song += "/";

+         song += bitrate;

+         song += "Kbps]";

+         m_SongListBox.AddString((LPCTSTR) song);

+      }

+

+   }

+   m_SongListBox.SetCurSel(0);

+}

+

+void CWMPADialog::SelectCurrentSong()

+{

+   CWMPMedia media;

+   long index;

+   long count;

+

+   count = m_WMP.GetCurrentPlaylist().GetCount();

+   for (index = 0; index < count; index++) {

+      media = m_WMP.GetCurrentPlaylist().GetItem(index);

+      if (m_WMP.GetCurrentMedia().GetIsIdentical(media)) {

+         m_SongListBox.SetCurSel(index);

+      }

+   }

+}

+

+void CWMPADialog::UpdatePlayLists()

+{

+	// TODO: Add extra initialization here

+   CWMPPlaylistCollection pc = m_WMP.GetPlaylistCollection();

+   CWMPPlaylistArray pa = pc.getAll();

+   CWMPPlaylist playlist;

+

+   int index;

+   int count = pa.GetCount();

+   m_PlaylistBox.ResetContent();

+   for (index = 0; index < count; index++) {

+      playlist = pa.Item(index);

+      m_PlaylistBox.AddString((LPCTSTR) playlist.GetName());

+   }

+}

+

+

+void CWMPADialog::OnPlayStateChangeWmp(long NewState)

+{

+	// TODO: Add your control notification handler code here

+}

+

+void CWMPADialog::OnSize(UINT nType, int cx, int cy)

+{

+	CDialog::OnSize(nType, cx, cy);

+	// TODO: Add your message handler code here

+   switch (nType) {

+      case SIZE_MINIMIZED:

+         break;

+

+      case SIZE_RESTORED:

+         Shell_NotifyIcon(NIM_DELETE, &nid);

+         break;

+

+      default:

+         break;

+   }

+}

+

+LRESULT CWMPADialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

+{

+   // TODO: Add your specialized code here and/or call the base class

+   switch (message) {

+      case WM_TRAY_ICON:

+         switch (lParam) {

+            case WM_LBUTTONDBLCLK:

+               trayClicked = TRUE;

+               break;

+

+            case WM_LBUTTONUP:

+               if (trayClicked == TRUE) {

+                  ShowWindow(SW_RESTORE);

+               }

+               break;

+

+            default:

+               trayClicked = FALSE;

+               break;

+         }

+         return(TRUE);

+         break;

+

+      default:

+         return CDialog::WindowProc(message, wParam, lParam);

+         break;

+   }

+}

+

+void CWMPADialog::DeleteTrayIcon()

+{

+   Shell_NotifyIcon(NIM_DELETE, &nid);

+}

diff --git a/plugins/wmpa/wmpadialog.h b/plugins/wmpa/wmpadialog.h
new file mode 100644
index 00000000..43e9a66a
--- /dev/null
+++ b/plugins/wmpa/wmpadialog.h
@@ -0,0 +1,91 @@
+/******************************************************************

+* $Id$

+*

+* $Log$

+*

+* Copyright © 2005 David Cullen, All rights reserved

+*

+******************************************************************/

+//{{AFX_INCLUDES()

+#include "wmpplayer4.h"

+//}}AFX_INCLUDES

+#if !defined(AFX_WMPADIALOG_H__D3838BCC_9E26_4FC0_BD42_C8D8EDF057E3__INCLUDED_)

+#define AFX_WMPADIALOG_H__D3838BCC_9E26_4FC0_BD42_C8D8EDF057E3__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// WMPADialog.h : header file

+//

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPADialog dialog

+

+class CWMPADialog : public CDialog

+{

+// Construction

+public:

+	CWMPADialog(CWnd* pParent = NULL);   // standard constructor

+   virtual void OnCancel();

+   void UpdatePlayLists();

+   void UpdateSongList();

+   void SelectCurrentSong();

+   void DeleteTrayIcon();

+   BOOL autoAnnounce;

+   HICON m_hIcon;

+

+private:

+   BOOL trayInit;

+   BOOL trayClicked;

+   NOTIFYICONDATA nid;

+

+public:

+// Dialog Data

+	//{{AFX_DATA(CWMPADialog)

+	enum { IDD = IDD_WMPADIALOG };

+	CListBox	m_SongListBox;

+	CListBox	m_PlaylistBox;

+	CWMPPlayer4	m_WMP;

+	//}}AFX_DATA

+

+

+// Overrides

+	// ClassWizard generated virtual function overrides

+	//{{AFX_VIRTUAL(CWMPADialog)

+	public:

+	virtual void OnFinalRelease();

+	protected:

+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

+	virtual void PostNcDestroy();

+	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

+	//}}AFX_VIRTUAL

+

+// Implementation

+protected:

+

+	// Generated message map functions

+	//{{AFX_MSG(CWMPADialog)

+	afx_msg void OnDblclkPlaylist();

+	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);

+	virtual BOOL OnInitDialog();

+	afx_msg void OnClose();

+	afx_msg void OnDblclkSonglist();

+	afx_msg void OnCurrentItemChangeWmp(LPDISPATCH pdispMedia);

+	afx_msg void OnDestroy();

+	afx_msg void OnPlayStateChangeWmp(long NewState);

+	afx_msg void OnSize(UINT nType, int cx, int cy);

+	DECLARE_EVENTSINK_MAP()

+	//}}AFX_MSG

+	DECLARE_MESSAGE_MAP()

+	// Generated OLE dispatch map functions

+	//{{AFX_DISPATCH(CWMPADialog)

+		// NOTE - the ClassWizard will add and remove member functions here.

+	//}}AFX_DISPATCH

+	DECLARE_DISPATCH_MAP()

+	DECLARE_INTERFACE_MAP()

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPADIALOG_H__D3838BCC_9E26_4FC0_BD42_C8D8EDF057E3__INCLUDED_)

diff --git a/plugins/wmpa/wmpcdrom.cpp b/plugins/wmpa/wmpcdrom.cpp
new file mode 100644
index 00000000..121f0535
--- /dev/null
+++ b/plugins/wmpa/wmpcdrom.cpp
@@ -0,0 +1,37 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpcdrom.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpplaylist.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdrom properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdrom operations

+

+CString CWMPCdrom::GetDriveSpecifier()

+{

+	CString result;

+	InvokeHelper(0xfb, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+CWMPPlaylist CWMPCdrom::GetPlaylist()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0xfc, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlaylist(pDispatch);

+}

+

+void CWMPCdrom::eject()

+{

+	InvokeHelper(0xfd, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

diff --git a/plugins/wmpa/wmpcdrom.h b/plugins/wmpa/wmpcdrom.h
new file mode 100644
index 00000000..f52f8f10
--- /dev/null
+++ b/plugins/wmpa/wmpcdrom.h
@@ -0,0 +1,39 @@
+#if !defined(AFX_WMPCDROM_H__B7B13CE9_E69E_4D54_9370_CCA2D4A42532__INCLUDED_)

+#define AFX_WMPCDROM_H__B7B13CE9_E69E_4D54_9370_CCA2D4A42532__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPPlaylist;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdrom wrapper class

+

+class CWMPCdrom : public COleDispatchDriver

+{

+public:

+	CWMPCdrom() {}		// Calls COleDispatchDriver default constructor

+	CWMPCdrom(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPCdrom(const CWMPCdrom& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	CString GetDriveSpecifier();

+	CWMPPlaylist GetPlaylist();

+	void eject();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPCDROM_H__B7B13CE9_E69E_4D54_9370_CCA2D4A42532__INCLUDED_)

diff --git a/plugins/wmpa/wmpcdromcollection.cpp b/plugins/wmpa/wmpcdromcollection.cpp
new file mode 100644
index 00000000..3e1f7e7d
--- /dev/null
+++ b/plugins/wmpa/wmpcdromcollection.cpp
@@ -0,0 +1,45 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpcdromcollection.h"

+

+// Dispatch interfaces referenced by this interface

+#include "WMPCdrom.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdromCollection properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdromCollection operations

+

+long CWMPCdromCollection::GetCount()

+{

+	long result;

+	InvokeHelper(0x12d, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CWMPCdrom CWMPCdromCollection::Item(long lIndex)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x12e, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		lIndex);

+	return CWMPCdrom(pDispatch);

+}

+

+CWMPCdrom CWMPCdromCollection::getByDriveSpecifier(LPCTSTR bstrDriveSpecifier)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x12f, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrDriveSpecifier);

+	return CWMPCdrom(pDispatch);

+}

diff --git a/plugins/wmpa/wmpcdromcollection.h b/plugins/wmpa/wmpcdromcollection.h
new file mode 100644
index 00000000..bdc32b9b
--- /dev/null
+++ b/plugins/wmpa/wmpcdromcollection.h
@@ -0,0 +1,39 @@
+#if !defined(AFX_WMPCDROMCOLLECTION_H__35F03E65_DBA5_47A8_84C1_DAA3D624A4D3__INCLUDED_)

+#define AFX_WMPCDROMCOLLECTION_H__35F03E65_DBA5_47A8_84C1_DAA3D624A4D3__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPCdrom;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPCdromCollection wrapper class

+

+class CWMPCdromCollection : public COleDispatchDriver

+{

+public:

+	CWMPCdromCollection() {}		// Calls COleDispatchDriver default constructor

+	CWMPCdromCollection(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPCdromCollection(const CWMPCdromCollection& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetCount();

+	CWMPCdrom Item(long lIndex);

+	CWMPCdrom getByDriveSpecifier(LPCTSTR bstrDriveSpecifier);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPCDROMCOLLECTION_H__35F03E65_DBA5_47A8_84C1_DAA3D624A4D3__INCLUDED_)

diff --git a/plugins/wmpa/wmpclosedcaption.cpp b/plugins/wmpa/wmpclosedcaption.cpp
new file mode 100644
index 00000000..3ea2ec91
--- /dev/null
+++ b/plugins/wmpa/wmpclosedcaption.cpp
@@ -0,0 +1,75 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpclosedcaption.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPClosedCaption properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPClosedCaption operations

+

+CString CWMPClosedCaption::GetSAMIStyle()

+{

+	CString result;

+	InvokeHelper(0x3b7, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPClosedCaption::SetSAMIStyle(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3b7, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+CString CWMPClosedCaption::GetSAMILang()

+{

+	CString result;

+	InvokeHelper(0x3b8, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPClosedCaption::SetSAMILang(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3b8, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+CString CWMPClosedCaption::GetSAMIFileName()

+{

+	CString result;

+	InvokeHelper(0x3b9, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPClosedCaption::SetSAMIFileName(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3b9, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+CString CWMPClosedCaption::GetCaptioningId()

+{

+	CString result;

+	InvokeHelper(0x3ba, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPClosedCaption::SetCaptioningId(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3ba, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

diff --git a/plugins/wmpa/wmpclosedcaption.h b/plugins/wmpa/wmpclosedcaption.h
new file mode 100644
index 00000000..c604c12f
--- /dev/null
+++ b/plugins/wmpa/wmpclosedcaption.h
@@ -0,0 +1,40 @@
+#if !defined(AFX_WMPCLOSEDCAPTION_H__FC0A9836_7517_4898_B25C_74C76E80CE3D__INCLUDED_)

+#define AFX_WMPCLOSEDCAPTION_H__FC0A9836_7517_4898_B25C_74C76E80CE3D__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPClosedCaption wrapper class

+

+class CWMPClosedCaption : public COleDispatchDriver

+{

+public:

+	CWMPClosedCaption() {}		// Calls COleDispatchDriver default constructor

+	CWMPClosedCaption(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPClosedCaption(const CWMPClosedCaption& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	CString GetSAMIStyle();

+	void SetSAMIStyle(LPCTSTR lpszNewValue);

+	CString GetSAMILang();

+	void SetSAMILang(LPCTSTR lpszNewValue);

+	CString GetSAMIFileName();

+	void SetSAMIFileName(LPCTSTR lpszNewValue);

+	CString GetCaptioningId();

+	void SetCaptioningId(LPCTSTR lpszNewValue);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPCLOSEDCAPTION_H__FC0A9836_7517_4898_B25C_74C76E80CE3D__INCLUDED_)

diff --git a/plugins/wmpa/wmpcontrols.cpp b/plugins/wmpa/wmpcontrols.cpp
new file mode 100644
index 00000000..1b3046d0
--- /dev/null
+++ b/plugins/wmpa/wmpcontrols.cpp
@@ -0,0 +1,123 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpcontrols.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpmedia.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPControls properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPControls operations

+

+BOOL CWMPControls::GetIsAvailable(LPCTSTR bstrItem)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3e, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,

+		bstrItem);

+	return result;

+}

+

+void CWMPControls::play()

+{

+	InvokeHelper(0x33, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPControls::stop()

+{

+	InvokeHelper(0x34, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPControls::pause()

+{

+	InvokeHelper(0x35, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPControls::fastForward()

+{

+	InvokeHelper(0x36, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPControls::fastReverse()

+{

+	InvokeHelper(0x37, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+double CWMPControls::GetCurrentPosition()

+{

+	double result;

+	InvokeHelper(0x38, DISPATCH_PROPERTYGET, VT_R8, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPControls::SetCurrentPosition(double newValue)

+{

+	static BYTE parms[] =

+		VTS_R8;

+	InvokeHelper(0x38, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 newValue);

+}

+

+CString CWMPControls::GetCurrentPositionString()

+{

+	CString result;

+	InvokeHelper(0x39, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPControls::next()

+{

+	InvokeHelper(0x3a, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPControls::previous()

+{

+	InvokeHelper(0x3b, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+CWMPMedia CWMPControls::GetCurrentItem()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x3c, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPMedia(pDispatch);

+}

+

+void CWMPControls::SetCurrentItem(LPDISPATCH newValue)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x3c, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 newValue);

+}

+

+long CWMPControls::GetCurrentMarker()

+{

+	long result;

+	InvokeHelper(0x3d, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPControls::SetCurrentMarker(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x3d, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+void CWMPControls::playItem(LPDISPATCH pIWMPMedia)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x3f, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pIWMPMedia);

+}

diff --git a/plugins/wmpa/wmpcontrols.h b/plugins/wmpa/wmpcontrols.h
new file mode 100644
index 00000000..b793bcb1
--- /dev/null
+++ b/plugins/wmpa/wmpcontrols.h
@@ -0,0 +1,52 @@
+#if !defined(AFX_WMPCONTROLS_H__234DACEF_6ED9_481D_B7E8_03653189E9B2__INCLUDED_)

+#define AFX_WMPCONTROLS_H__234DACEF_6ED9_481D_B7E8_03653189E9B2__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPMedia;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPControls wrapper class

+

+class CWMPControls : public COleDispatchDriver

+{

+public:

+	CWMPControls() {}		// Calls COleDispatchDriver default constructor

+	CWMPControls(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPControls(const CWMPControls& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	BOOL GetIsAvailable(LPCTSTR bstrItem);

+	void play();

+	void stop();

+	void pause();

+	void fastForward();

+	void fastReverse();

+	double GetCurrentPosition();

+	void SetCurrentPosition(double newValue);

+	CString GetCurrentPositionString();

+	void next();

+	void previous();

+	CWMPMedia GetCurrentItem();

+	void SetCurrentItem(LPDISPATCH newValue);

+	long GetCurrentMarker();

+	void SetCurrentMarker(long nNewValue);

+	void playItem(LPDISPATCH pIWMPMedia);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPCONTROLS_H__234DACEF_6ED9_481D_B7E8_03653189E9B2__INCLUDED_)

diff --git a/plugins/wmpa/wmpdvd.cpp b/plugins/wmpa/wmpdvd.cpp
new file mode 100644
index 00000000..0eb48f6f
--- /dev/null
+++ b/plugins/wmpa/wmpdvd.cpp
@@ -0,0 +1,52 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpdvd.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPDVD properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPDVD operations

+

+BOOL CWMPDVD::GetIsAvailable(LPCTSTR bstrItem)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x3e9, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,

+		bstrItem);

+	return result;

+}

+

+CString CWMPDVD::GetDomain()

+{

+	CString result;

+	InvokeHelper(0x3ea, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPDVD::topMenu()

+{

+	InvokeHelper(0x3eb, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPDVD::titleMenu()

+{

+	InvokeHelper(0x3ec, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPDVD::back()

+{

+	InvokeHelper(0x3ed, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPDVD::resume()

+{

+	InvokeHelper(0x3ee, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

diff --git a/plugins/wmpa/wmpdvd.h b/plugins/wmpa/wmpdvd.h
new file mode 100644
index 00000000..4710536a
--- /dev/null
+++ b/plugins/wmpa/wmpdvd.h
@@ -0,0 +1,38 @@
+#if !defined(AFX_WMPDVD_H__E83D86CA_08B8_4ACA_A434_0837BA71E3CA__INCLUDED_)

+#define AFX_WMPDVD_H__E83D86CA_08B8_4ACA_A434_0837BA71E3CA__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPDVD wrapper class

+

+class CWMPDVD : public COleDispatchDriver

+{

+public:

+	CWMPDVD() {}		// Calls COleDispatchDriver default constructor

+	CWMPDVD(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPDVD(const CWMPDVD& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	BOOL GetIsAvailable(LPCTSTR bstrItem);

+	CString GetDomain();

+	void topMenu();

+	void titleMenu();

+	void back();

+	void resume();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPDVD_H__E83D86CA_08B8_4ACA_A434_0837BA71E3CA__INCLUDED_)

diff --git a/plugins/wmpa/wmperror.cpp b/plugins/wmpa/wmperror.cpp
new file mode 100644
index 00000000..2fce2b59
--- /dev/null
+++ b/plugins/wmpa/wmperror.cpp
@@ -0,0 +1,45 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmperror.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmperroritem.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPError properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPError operations

+

+void CWMPError::clearErrorQueue()

+{

+	InvokeHelper(0x353, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+long CWMPError::GetErrorCount()

+{

+	long result;

+	InvokeHelper(0x354, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CWMPErrorItem CWMPError::GetItem(long dwIndex)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x355, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, parms,

+		dwIndex);

+	return CWMPErrorItem(pDispatch);

+}

+

+void CWMPError::webHelp()

+{

+	InvokeHelper(0x356, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

diff --git a/plugins/wmpa/wmperror.h b/plugins/wmpa/wmperror.h
new file mode 100644
index 00000000..94ee2fff
--- /dev/null
+++ b/plugins/wmpa/wmperror.h
@@ -0,0 +1,40 @@
+#if !defined(AFX_WMPERROR_H__1E72AC7F_E0AC_4100_B7EF_A5B0D8FA75C3__INCLUDED_)

+#define AFX_WMPERROR_H__1E72AC7F_E0AC_4100_B7EF_A5B0D8FA75C3__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPErrorItem;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPError wrapper class

+

+class CWMPError : public COleDispatchDriver

+{

+public:

+	CWMPError() {}		// Calls COleDispatchDriver default constructor

+	CWMPError(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPError(const CWMPError& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	void clearErrorQueue();

+	long GetErrorCount();

+	CWMPErrorItem GetItem(long dwIndex);

+	void webHelp();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPERROR_H__1E72AC7F_E0AC_4100_B7EF_A5B0D8FA75C3__INCLUDED_)

diff --git a/plugins/wmpa/wmperroritem.cpp b/plugins/wmpa/wmperroritem.cpp
new file mode 100644
index 00000000..86e9740c
--- /dev/null
+++ b/plugins/wmpa/wmperroritem.cpp
@@ -0,0 +1,50 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmperroritem.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPErrorItem properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPErrorItem operations

+

+long CWMPErrorItem::GetErrorCode()

+{

+	long result;

+	InvokeHelper(0x385, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPErrorItem::GetErrorDescription()

+{

+	CString result;

+	InvokeHelper(0x386, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+VARIANT CWMPErrorItem::GetErrorContext()

+{

+	VARIANT result;

+	InvokeHelper(0x387, DISPATCH_PROPERTYGET, VT_VARIANT, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPErrorItem::GetRemedy()

+{

+	long result;

+	InvokeHelper(0x388, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPErrorItem::GetCustomUrl()

+{

+	CString result;

+	InvokeHelper(0x389, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

diff --git a/plugins/wmpa/wmperroritem.h b/plugins/wmpa/wmperroritem.h
new file mode 100644
index 00000000..de66dc9b
--- /dev/null
+++ b/plugins/wmpa/wmperroritem.h
@@ -0,0 +1,37 @@
+#if !defined(AFX_WMPERRORITEM_H__9399BDE5_C96D_43D3_BF02_E7A5850421B4__INCLUDED_)

+#define AFX_WMPERRORITEM_H__9399BDE5_C96D_43D3_BF02_E7A5850421B4__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPErrorItem wrapper class

+

+class CWMPErrorItem : public COleDispatchDriver

+{

+public:

+	CWMPErrorItem() {}		// Calls COleDispatchDriver default constructor

+	CWMPErrorItem(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPErrorItem(const CWMPErrorItem& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetErrorCode();

+	CString GetErrorDescription();

+	VARIANT GetErrorContext();

+	long GetRemedy();

+	CString GetCustomUrl();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPERRORITEM_H__9399BDE5_C96D_43D3_BF02_E7A5850421B4__INCLUDED_)

diff --git a/plugins/wmpa/wmpmedia.cpp b/plugins/wmpa/wmpmedia.cpp
new file mode 100644
index 00000000..63503ab8
--- /dev/null
+++ b/plugins/wmpa/wmpmedia.cpp
@@ -0,0 +1,167 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpmedia.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMedia properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMedia operations

+

+BOOL CWMPMedia::GetIsIdentical(LPDISPATCH pIWMPMedia)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x2fb, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,

+		pIWMPMedia);

+	return result;

+}

+

+CString CWMPMedia::GetSourceURL()

+{

+	CString result;

+	InvokeHelper(0x2ef, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPMedia::GetName()

+{

+	CString result;

+	InvokeHelper(0x2fc, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPMedia::SetName(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x2fc, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+long CWMPMedia::GetImageSourceWidth()

+{

+	long result;

+	InvokeHelper(0x2f0, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPMedia::GetImageSourceHeight()

+{

+	long result;

+	InvokeHelper(0x2f1, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPMedia::GetMarkerCount()

+{

+	long result;

+	InvokeHelper(0x2f2, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+double CWMPMedia::getMarkerTime(long MarkerNum)

+{

+	double result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x2f3, DISPATCH_METHOD, VT_R8, (void*)&result, parms,

+		MarkerNum);

+	return result;

+}

+

+CString CWMPMedia::getMarkerName(long MarkerNum)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x2f4, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		MarkerNum);

+	return result;

+}

+

+double CWMPMedia::GetDuration()

+{

+	double result;

+	InvokeHelper(0x2f5, DISPATCH_PROPERTYGET, VT_R8, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPMedia::GetDurationString()

+{

+	CString result;

+	InvokeHelper(0x2f6, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPMedia::GetAttributeCount()

+{

+	long result;

+	InvokeHelper(0x2f7, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPMedia::getAttributeName(long lIndex)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x2f8, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		lIndex);

+	return result;

+}

+

+CString CWMPMedia::getItemInfo(LPCTSTR bstrItemName)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x2f9, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		bstrItemName);

+	return result;

+}

+

+void CWMPMedia::setItemInfo(LPCTSTR bstrItemName, LPCTSTR bstrVal)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x2fa, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrItemName, bstrVal);

+}

+

+CString CWMPMedia::getItemInfoByAtom(long lAtom)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x2fd, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		lAtom);

+	return result;

+}

+

+BOOL CWMPMedia::isMemberOf(LPDISPATCH pPlaylist)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x2fe, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		pPlaylist);

+	return result;

+}

+

+BOOL CWMPMedia::isReadOnlyItem(LPCTSTR bstrItemName)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x2ff, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		bstrItemName);

+	return result;

+}

diff --git a/plugins/wmpa/wmpmedia.h b/plugins/wmpa/wmpmedia.h
new file mode 100644
index 00000000..3503c403
--- /dev/null
+++ b/plugins/wmpa/wmpmedia.h
@@ -0,0 +1,50 @@
+#if !defined(AFX_WMPMEDIA_H__7736565E_C037_498E_89F1_9696912C5998__INCLUDED_)

+#define AFX_WMPMEDIA_H__7736565E_C037_498E_89F1_9696912C5998__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMedia wrapper class

+

+class CWMPMedia : public COleDispatchDriver

+{

+public:

+	CWMPMedia() {}		// Calls COleDispatchDriver default constructor

+	CWMPMedia(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPMedia(const CWMPMedia& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	BOOL GetIsIdentical(LPDISPATCH pIWMPMedia);

+	CString GetSourceURL();

+	CString GetName();

+	void SetName(LPCTSTR lpszNewValue);

+	long GetImageSourceWidth();

+	long GetImageSourceHeight();

+	long GetMarkerCount();

+	double getMarkerTime(long MarkerNum);

+	CString getMarkerName(long MarkerNum);

+	double GetDuration();

+	CString GetDurationString();

+	long GetAttributeCount();

+	CString getAttributeName(long lIndex);

+	CString getItemInfo(LPCTSTR bstrItemName);

+	void setItemInfo(LPCTSTR bstrItemName, LPCTSTR bstrVal);

+	CString getItemInfoByAtom(long lAtom);

+	BOOL isMemberOf(LPDISPATCH pPlaylist);

+	BOOL isReadOnlyItem(LPCTSTR bstrItemName);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPMEDIA_H__7736565E_C037_498E_89F1_9696912C5998__INCLUDED_)

diff --git a/plugins/wmpa/wmpmediacollection.cpp b/plugins/wmpa/wmpmediacollection.cpp
new file mode 100644
index 00000000..d50da652
--- /dev/null
+++ b/plugins/wmpa/wmpmediacollection.cpp
@@ -0,0 +1,133 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpmediacollection.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpmedia.h"

+#include "wmpplaylist.h"

+#include "wmpstringcollection.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMediaCollection properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMediaCollection operations

+

+CWMPMedia CWMPMediaCollection::add(LPCTSTR bstrURL)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c4, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrURL);

+	return CWMPMedia(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getAll()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x1c5, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getByName(LPCTSTR bstrName)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c6, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrName);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getByGenre(LPCTSTR bstrGenre)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c7, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrGenre);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getByAuthor(LPCTSTR bstrAuthor)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c8, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrAuthor);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getByAlbum(LPCTSTR bstrAlbum)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c9, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrAlbum);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylist CWMPMediaCollection::getByAttribute(LPCTSTR bstrAttribute, LPCTSTR bstrValue)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x1ca, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrAttribute, bstrValue);

+	return CWMPPlaylist(pDispatch);

+}

+

+void CWMPMediaCollection::remove(LPDISPATCH pItem, BOOL varfDeleteFile)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH VTS_BOOL;

+	InvokeHelper(0x1cb, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pItem, varfDeleteFile);

+}

+

+CWMPStringCollection CWMPMediaCollection::getAttributeStringCollection(LPCTSTR bstrAttribute, LPCTSTR bstrMediaType)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x1cd, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrAttribute, bstrMediaType);

+	return CWMPStringCollection(pDispatch);

+}

+

+long CWMPMediaCollection::getMediaAtom(LPCTSTR bstrItemName)

+{

+	long result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1d6, DISPATCH_METHOD, VT_I4, (void*)&result, parms,

+		bstrItemName);

+	return result;

+}

+

+void CWMPMediaCollection::setDeleted(LPDISPATCH pItem, BOOL varfIsDeleted)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH VTS_BOOL;

+	InvokeHelper(0x1d7, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pItem, varfIsDeleted);

+}

+

+BOOL CWMPMediaCollection::isDeleted(LPDISPATCH pItem)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x1d8, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		pItem);

+	return result;

+}

diff --git a/plugins/wmpa/wmpmediacollection.h b/plugins/wmpa/wmpmediacollection.h
new file mode 100644
index 00000000..aa91026a
--- /dev/null
+++ b/plugins/wmpa/wmpmediacollection.h
@@ -0,0 +1,50 @@
+#if !defined(AFX_WMPMEDIACOLLECTION_H__8C47EB0E_4638_46DA_A405_415AEAE509CE__INCLUDED_)

+#define AFX_WMPMEDIACOLLECTION_H__8C47EB0E_4638_46DA_A405_415AEAE509CE__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPMedia;

+class CWMPPlaylist;

+class CWMPStringCollection;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPMediaCollection wrapper class

+

+class CWMPMediaCollection : public COleDispatchDriver

+{

+public:

+	CWMPMediaCollection() {}		// Calls COleDispatchDriver default constructor

+	CWMPMediaCollection(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPMediaCollection(const CWMPMediaCollection& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	CWMPMedia add(LPCTSTR bstrURL);

+	CWMPPlaylist getAll();

+	CWMPPlaylist getByName(LPCTSTR bstrName);

+	CWMPPlaylist getByGenre(LPCTSTR bstrGenre);

+	CWMPPlaylist getByAuthor(LPCTSTR bstrAuthor);

+	CWMPPlaylist getByAlbum(LPCTSTR bstrAlbum);

+	CWMPPlaylist getByAttribute(LPCTSTR bstrAttribute, LPCTSTR bstrValue);

+	void remove(LPDISPATCH pItem, BOOL varfDeleteFile);

+	CWMPStringCollection getAttributeStringCollection(LPCTSTR bstrAttribute, LPCTSTR bstrMediaType);

+	long getMediaAtom(LPCTSTR bstrItemName);

+	void setDeleted(LPDISPATCH pItem, BOOL varfIsDeleted);

+	BOOL isDeleted(LPDISPATCH pItem);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPMEDIACOLLECTION_H__8C47EB0E_4638_46DA_A405_415AEAE509CE__INCLUDED_)

diff --git a/plugins/wmpa/wmpnetwork.cpp b/plugins/wmpa/wmpnetwork.cpp
new file mode 100644
index 00000000..87c4d413
--- /dev/null
+++ b/plugins/wmpa/wmpnetwork.cpp
@@ -0,0 +1,233 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpnetwork.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPNetwork properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPNetwork operations

+

+long CWMPNetwork::GetBandWidth()

+{

+	long result;

+	InvokeHelper(0x321, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetRecoveredPackets()

+{

+	long result;

+	InvokeHelper(0x322, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPNetwork::GetSourceProtocol()

+{

+	CString result;

+	InvokeHelper(0x323, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetReceivedPackets()

+{

+	long result;

+	InvokeHelper(0x324, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetLostPackets()

+{

+	long result;

+	InvokeHelper(0x325, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetReceptionQuality()

+{

+	long result;

+	InvokeHelper(0x326, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetBufferingCount()

+{

+	long result;

+	InvokeHelper(0x327, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetBufferingProgress()

+{

+	long result;

+	InvokeHelper(0x328, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetBufferingTime()

+{

+	long result;

+	InvokeHelper(0x329, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPNetwork::SetBufferingTime(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x329, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+long CWMPNetwork::GetFrameRate()

+{

+	long result;

+	InvokeHelper(0x32a, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetMaxBitRate()

+{

+	long result;

+	InvokeHelper(0x32b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetBitRate()

+{

+	long result;

+	InvokeHelper(0x32c, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::getProxySettings(LPCTSTR bstrProtocol)

+{

+	long result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x32d, DISPATCH_METHOD, VT_I4, (void*)&result, parms,

+		bstrProtocol);

+	return result;

+}

+

+void CWMPNetwork::setProxySettings(LPCTSTR bstrProtocol, long lProxySetting)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_I4;

+	InvokeHelper(0x32e, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrProtocol, lProxySetting);

+}

+

+CString CWMPNetwork::getProxyName(LPCTSTR bstrProtocol)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x32f, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		bstrProtocol);

+	return result;

+}

+

+void CWMPNetwork::setProxyName(LPCTSTR bstrProtocol, LPCTSTR bstrProxyName)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x330, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrProtocol, bstrProxyName);

+}

+

+long CWMPNetwork::getProxyPort(LPCTSTR bstrProtocol)

+{

+	long result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x331, DISPATCH_METHOD, VT_I4, (void*)&result, parms,

+		bstrProtocol);

+	return result;

+}

+

+void CWMPNetwork::setProxyPort(LPCTSTR bstrProtocol, long lProxyPort)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_I4;

+	InvokeHelper(0x332, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrProtocol, lProxyPort);

+}

+

+CString CWMPNetwork::getProxyExceptionList(LPCTSTR bstrProtocol)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x333, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		bstrProtocol);

+	return result;

+}

+

+void CWMPNetwork::setProxyExceptionList(LPCTSTR bstrProtocol, LPCTSTR pbstrExceptionList)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x334, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrProtocol, pbstrExceptionList);

+}

+

+BOOL CWMPNetwork::getProxyBypassForLocal(LPCTSTR bstrProtocol)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x335, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		bstrProtocol);

+	return result;

+}

+

+void CWMPNetwork::setProxyBypassForLocal(LPCTSTR bstrProtocol, BOOL fBypassForLocal)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BOOL;

+	InvokeHelper(0x336, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrProtocol, fBypassForLocal);

+}

+

+long CWMPNetwork::GetMaxBandwidth()

+{

+	long result;

+	InvokeHelper(0x337, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPNetwork::SetMaxBandwidth(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x337, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+long CWMPNetwork::GetDownloadProgress()

+{

+	long result;

+	InvokeHelper(0x338, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetEncodedFrameRate()

+{

+	long result;

+	InvokeHelper(0x339, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPNetwork::GetFramesSkipped()

+{

+	long result;

+	InvokeHelper(0x33a, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

diff --git a/plugins/wmpa/wmpnetwork.h b/plugins/wmpa/wmpnetwork.h
new file mode 100644
index 00000000..1a0e0427
--- /dev/null
+++ b/plugins/wmpa/wmpnetwork.h
@@ -0,0 +1,60 @@
+#if !defined(AFX_WMPNETWORK_H__50BDAB41_9F78_492A_8A5E_27543B0C0CAF__INCLUDED_)

+#define AFX_WMPNETWORK_H__50BDAB41_9F78_492A_8A5E_27543B0C0CAF__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPNetwork wrapper class

+

+class CWMPNetwork : public COleDispatchDriver

+{

+public:

+	CWMPNetwork() {}		// Calls COleDispatchDriver default constructor

+	CWMPNetwork(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPNetwork(const CWMPNetwork& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetBandWidth();

+	long GetRecoveredPackets();

+	CString GetSourceProtocol();

+	long GetReceivedPackets();

+	long GetLostPackets();

+	long GetReceptionQuality();

+	long GetBufferingCount();

+	long GetBufferingProgress();

+	long GetBufferingTime();

+	void SetBufferingTime(long nNewValue);

+	long GetFrameRate();

+	long GetMaxBitRate();

+	long GetBitRate();

+	long getProxySettings(LPCTSTR bstrProtocol);

+	void setProxySettings(LPCTSTR bstrProtocol, long lProxySetting);

+	CString getProxyName(LPCTSTR bstrProtocol);

+	void setProxyName(LPCTSTR bstrProtocol, LPCTSTR bstrProxyName);

+	long getProxyPort(LPCTSTR bstrProtocol);

+	void setProxyPort(LPCTSTR bstrProtocol, long lProxyPort);

+	CString getProxyExceptionList(LPCTSTR bstrProtocol);

+	void setProxyExceptionList(LPCTSTR bstrProtocol, LPCTSTR pbstrExceptionList);

+	BOOL getProxyBypassForLocal(LPCTSTR bstrProtocol);

+	void setProxyBypassForLocal(LPCTSTR bstrProtocol, BOOL fBypassForLocal);

+	long GetMaxBandwidth();

+	void SetMaxBandwidth(long nNewValue);

+	long GetDownloadProgress();

+	long GetEncodedFrameRate();

+	long GetFramesSkipped();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPNETWORK_H__50BDAB41_9F78_492A_8A5E_27543B0C0CAF__INCLUDED_)

diff --git a/plugins/wmpa/wmpplayer4.cpp b/plugins/wmpa/wmpplayer4.cpp
new file mode 100644
index 00000000..40050678
--- /dev/null
+++ b/plugins/wmpa/wmpplayer4.cpp
@@ -0,0 +1,321 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpplayer4.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpcontrols.h"

+#include "WMPSettings.h"

+#include "wmpmedia.h"

+#include "wmpmediacollection.h"

+#include "wmpplaylistcollection.h"

+#include "wmpnetwork.h"

+#include "wmpplaylist.h"

+#include "wmpcdromcollection.h"

+#include "wmpclosedcaption.h"

+#include "WMPError.h"

+#include "wmpdvd.h"

+#include "WMPPlayerApplication.h"

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayer4

+

+IMPLEMENT_DYNCREATE(CWMPPlayer4, CWnd)

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayer4 properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayer4 operations

+

+void CWMPPlayer4::close()

+{

+	InvokeHelper(0x3, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+CString CWMPPlayer4::GetUrl()

+{

+	CString result;

+	InvokeHelper(0x1, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetUrl(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+long CWMPPlayer4::GetOpenState()

+{

+	long result;

+	InvokeHelper(0x2, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+long CWMPPlayer4::GetPlayState()

+{

+	long result;

+	InvokeHelper(0xa, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CWMPControls CWMPPlayer4::GetControls()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x4, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPControls(pDispatch);

+}

+

+CWMPSettings CWMPPlayer4::GetSettings()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x5, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPSettings(pDispatch);

+}

+

+CWMPMedia CWMPPlayer4::GetCurrentMedia()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x6, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPMedia(pDispatch);

+}

+

+void CWMPPlayer4::SetCurrentMedia(LPDISPATCH newValue)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x6, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 newValue);

+}

+

+CWMPMediaCollection CWMPPlayer4::GetMediaCollection()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x8, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPMediaCollection(pDispatch);

+}

+

+CWMPPlaylistCollection CWMPPlayer4::GetPlaylistCollection()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x9, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlaylistCollection(pDispatch);

+}

+

+CString CWMPPlayer4::GetVersionInfo()

+{

+	CString result;

+	InvokeHelper(0xb, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::launchURL(LPCTSTR bstrURL)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0xc, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrURL);

+}

+

+CWMPNetwork CWMPPlayer4::GetNetwork()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x7, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPNetwork(pDispatch);

+}

+

+CWMPPlaylist CWMPPlayer4::GetCurrentPlaylist()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0xd, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlaylist(pDispatch);

+}

+

+void CWMPPlayer4::SetCurrentPlaylist(LPDISPATCH newValue)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0xd, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 newValue);

+}

+

+CWMPCdromCollection CWMPPlayer4::GetCdromCollection()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0xe, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPCdromCollection(pDispatch);

+}

+

+CWMPClosedCaption CWMPPlayer4::GetClosedCaption()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0xf, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPClosedCaption(pDispatch);

+}

+

+BOOL CWMPPlayer4::GetIsOnline()

+{

+	BOOL result;

+	InvokeHelper(0x10, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+CWMPError CWMPPlayer4::GetError()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x11, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPError(pDispatch);

+}

+

+CString CWMPPlayer4::GetStatus()

+{

+	CString result;

+	InvokeHelper(0x12, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+CWMPDVD CWMPPlayer4::GetDvd()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x28, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPDVD(pDispatch);

+}

+

+CWMPPlaylist CWMPPlayer4::newPlaylist(LPCTSTR bstrName, LPCTSTR bstrURL)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0x29, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrName, bstrURL);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPMedia CWMPPlayer4::newMedia(LPCTSTR bstrURL)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x2a, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrURL);

+	return CWMPMedia(pDispatch);

+}

+

+BOOL CWMPPlayer4::GetEnabled()

+{

+	BOOL result;

+	InvokeHelper(0x13, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetEnabled(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x13, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+BOOL CWMPPlayer4::GetFullScreen()

+{

+	BOOL result;

+	InvokeHelper(0x15, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetFullScreen(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x15, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+BOOL CWMPPlayer4::GetEnableContextMenu()

+{

+	BOOL result;

+	InvokeHelper(0x16, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetEnableContextMenu(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x16, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+void CWMPPlayer4::SetUiMode(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x17, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+CString CWMPPlayer4::GetUiMode()

+{

+	CString result;

+	InvokeHelper(0x17, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+BOOL CWMPPlayer4::GetStretchToFit()

+{

+	BOOL result;

+	InvokeHelper(0x18, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetStretchToFit(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x18, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+BOOL CWMPPlayer4::GetWindowlessVideo()

+{

+	BOOL result;

+	InvokeHelper(0x19, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlayer4::SetWindowlessVideo(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x19, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+BOOL CWMPPlayer4::GetIsRemote()

+{

+	BOOL result;

+	InvokeHelper(0x1a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+CWMPPlayerApplication CWMPPlayer4::GetPlayerApplication()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x1b, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlayerApplication(pDispatch);

+}

+

+void CWMPPlayer4::openPlayer(LPCTSTR bstrURL)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x1c, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrURL);

+}

diff --git a/plugins/wmpa/wmpplayer4.h b/plugins/wmpa/wmpplayer4.h
new file mode 100644
index 00000000..687d9361
--- /dev/null
+++ b/plugins/wmpa/wmpplayer4.h
@@ -0,0 +1,104 @@
+#if !defined(AFX_WMPPLAYER4_H__A318AE12_803B_4EED_B586_1395637CDD35__INCLUDED_)

+#define AFX_WMPPLAYER4_H__A318AE12_803B_4EED_B586_1395637CDD35__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPControls;

+class CWMPSettings;

+class CWMPMedia;

+class CWMPMediaCollection;

+class CWMPPlaylistCollection;

+class CWMPNetwork;

+class CWMPPlaylist;

+class CWMPCdromCollection;

+class CWMPClosedCaption;

+class CWMPError;

+class CWMPDVD;

+class CWMPPlayerApplication;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayer4 wrapper class

+

+class CWMPPlayer4 : public CWnd

+{

+protected:

+	DECLARE_DYNCREATE(CWMPPlayer4)

+public:

+	CLSID const& GetClsid()

+	{

+		static CLSID const clsid

+			= { 0x6bf52a52, 0x394a, 0x11d3, { 0xb1, 0x53, 0x0, 0xc0, 0x4f, 0x79, 0xfa, 0xa6 } };

+		return clsid;

+	}

+	/*virtual BOOL Create(LPCTSTR lpszClassName,

+		LPCTSTR lpszWindowName, DWORD dwStyle,

+		const RECT& rect,

+		CWnd* pParentWnd, UINT nID,

+		CCreateContext* pContext = NULL)

+	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }*/

+

+    BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,

+		const RECT& rect, CWnd* pParentWnd, UINT nID,

+		CFile* pPersist = NULL, BOOL bStorage = FALSE,

+		BSTR bstrLicKey = NULL)

+	{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,

+		pPersist, bStorage, bstrLicKey); }

+

+// Attributes

+public:

+

+// Operations

+public:

+	void close();

+	CString GetUrl();

+	void SetUrl(LPCTSTR lpszNewValue);

+	long GetOpenState();

+	long GetPlayState();

+	CWMPControls GetControls();

+	CWMPSettings GetSettings();

+	CWMPMedia GetCurrentMedia();

+	void SetCurrentMedia(LPDISPATCH newValue);

+	CWMPMediaCollection GetMediaCollection();

+	CWMPPlaylistCollection GetPlaylistCollection();

+	CString GetVersionInfo();

+	void launchURL(LPCTSTR bstrURL);

+	CWMPNetwork GetNetwork();

+	CWMPPlaylist GetCurrentPlaylist();

+	void SetCurrentPlaylist(LPDISPATCH newValue);

+	CWMPCdromCollection GetCdromCollection();

+	CWMPClosedCaption GetClosedCaption();

+	BOOL GetIsOnline();

+	CWMPError GetError();

+	CString GetStatus();

+	CWMPDVD GetDvd();

+	CWMPPlaylist newPlaylist(LPCTSTR bstrName, LPCTSTR bstrURL);

+	CWMPMedia newMedia(LPCTSTR bstrURL);

+	BOOL GetEnabled();

+	void SetEnabled(BOOL bNewValue);

+	BOOL GetFullScreen();

+	void SetFullScreen(BOOL bNewValue);

+	BOOL GetEnableContextMenu();

+	void SetEnableContextMenu(BOOL bNewValue);

+	void SetUiMode(LPCTSTR lpszNewValue);

+	CString GetUiMode();

+	BOOL GetStretchToFit();

+	void SetStretchToFit(BOOL bNewValue);

+	BOOL GetWindowlessVideo();

+	void SetWindowlessVideo(BOOL bNewValue);

+	BOOL GetIsRemote();

+	CWMPPlayerApplication GetPlayerApplication();

+	void openPlayer(LPCTSTR bstrURL);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPPLAYER4_H__A318AE12_803B_4EED_B586_1395637CDD35__INCLUDED_)

diff --git a/plugins/wmpa/wmpplayerapplication.cpp b/plugins/wmpa/wmpplayerapplication.cpp
new file mode 100644
index 00000000..d47956a7
--- /dev/null
+++ b/plugins/wmpa/wmpplayerapplication.cpp
@@ -0,0 +1,39 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpplayerapplication.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayerApplication properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayerApplication operations

+

+void CWMPPlayerApplication::switchToPlayerApplication()

+{

+	InvokeHelper(0x44d, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPPlayerApplication::switchToControl()

+{

+	InvokeHelper(0x44e, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+BOOL CWMPPlayerApplication::GetPlayerDocked()

+{

+	BOOL result;

+	InvokeHelper(0x44f, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+BOOL CWMPPlayerApplication::GetHasDisplay()

+{

+	BOOL result;

+	InvokeHelper(0x450, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

diff --git a/plugins/wmpa/wmpplayerapplication.h b/plugins/wmpa/wmpplayerapplication.h
new file mode 100644
index 00000000..96205aae
--- /dev/null
+++ b/plugins/wmpa/wmpplayerapplication.h
@@ -0,0 +1,36 @@
+#if !defined(AFX_WMPPLAYERAPPLICATION_H__A69CB85C_22A1_4A02_979D_3FFB61135553__INCLUDED_)

+#define AFX_WMPPLAYERAPPLICATION_H__A69CB85C_22A1_4A02_979D_3FFB61135553__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlayerApplication wrapper class

+

+class CWMPPlayerApplication : public COleDispatchDriver

+{

+public:

+	CWMPPlayerApplication() {}		// Calls COleDispatchDriver default constructor

+	CWMPPlayerApplication(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPPlayerApplication(const CWMPPlayerApplication& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	void switchToPlayerApplication();

+	void switchToControl();

+	BOOL GetPlayerDocked();

+	BOOL GetHasDisplay();

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPPLAYERAPPLICATION_H__A69CB85C_22A1_4A02_979D_3FFB61135553__INCLUDED_)

diff --git a/plugins/wmpa/wmpplaylist.cpp b/plugins/wmpa/wmpplaylist.cpp
new file mode 100644
index 00000000..9308aa5b
--- /dev/null
+++ b/plugins/wmpa/wmpplaylist.cpp
@@ -0,0 +1,132 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpplaylist.h"

+

+// Dispatch interfaces referenced by this interface

+#include "WMPMedia.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylist properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylist operations

+

+long CWMPPlaylist::GetCount()

+{

+	long result;

+	InvokeHelper(0xc9, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPPlaylist::GetName()

+{

+	CString result;

+	InvokeHelper(0xca, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPPlaylist::SetName(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0xca, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+long CWMPPlaylist::GetAttributeCount()

+{

+	long result;

+	InvokeHelper(0xd2, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPPlaylist::GetAttributeName(long lIndex)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0xd3, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, parms,

+		lIndex);

+	return result;

+}

+

+CWMPMedia CWMPPlaylist::GetItem(long lIndex)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0xd4, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&pDispatch, parms,

+		lIndex);

+	return CWMPMedia(pDispatch);

+}

+

+CString CWMPPlaylist::getItemInfo(LPCTSTR bstrName)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0xcb, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		bstrName);

+	return result;

+}

+

+void CWMPPlaylist::setItemInfo(LPCTSTR bstrName, LPCTSTR bstrValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BSTR;

+	InvokeHelper(0xcc, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrName, bstrValue);

+}

+

+BOOL CWMPPlaylist::GetIsIdentical(LPDISPATCH pIWMPPlaylist)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0xd5, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,

+		pIWMPPlaylist);

+	return result;

+}

+

+void CWMPPlaylist::clear()

+{

+	InvokeHelper(0xcd, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);

+}

+

+void CWMPPlaylist::insertItem(long lIndex, LPDISPATCH pIWMPMedia)

+{

+	static BYTE parms[] =

+		VTS_I4 VTS_DISPATCH;

+	InvokeHelper(0xce, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 lIndex, pIWMPMedia);

+}

+

+void CWMPPlaylist::appendItem(LPDISPATCH pIWMPMedia)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0xcf, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pIWMPMedia);

+}

+

+void CWMPPlaylist::removeItem(LPDISPATCH pIWMPMedia)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0xd0, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pIWMPMedia);

+}

+

+void CWMPPlaylist::moveItem(long lIndexOld, long lIndexNew)

+{

+	static BYTE parms[] =

+		VTS_I4 VTS_I4;

+	InvokeHelper(0xd1, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 lIndexOld, lIndexNew);

+}

diff --git a/plugins/wmpa/wmpplaylist.h b/plugins/wmpa/wmpplaylist.h
new file mode 100644
index 00000000..1d28ebd1
--- /dev/null
+++ b/plugins/wmpa/wmpplaylist.h
@@ -0,0 +1,50 @@
+#if !defined(AFX_WMPPLAYLIST_H__B739DAEE_6828_4128_8A0A_E6750502339C__INCLUDED_)

+#define AFX_WMPPLAYLIST_H__B739DAEE_6828_4128_8A0A_E6750502339C__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPMedia;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylist wrapper class

+

+class CWMPPlaylist : public COleDispatchDriver

+{

+public:

+	CWMPPlaylist() {}		// Calls COleDispatchDriver default constructor

+	CWMPPlaylist(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPPlaylist(const CWMPPlaylist& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetCount();

+	CString GetName();

+	void SetName(LPCTSTR lpszNewValue);

+	long GetAttributeCount();

+	CString GetAttributeName(long lIndex);

+	CWMPMedia GetItem(long lIndex);

+	CString getItemInfo(LPCTSTR bstrName);

+	void setItemInfo(LPCTSTR bstrName, LPCTSTR bstrValue);

+	BOOL GetIsIdentical(LPDISPATCH pIWMPPlaylist);

+	void clear();

+	void insertItem(long lIndex, LPDISPATCH pIWMPMedia);

+	void appendItem(LPDISPATCH pIWMPMedia);

+	void removeItem(LPDISPATCH pIWMPMedia);

+	void moveItem(long lIndexOld, long lIndexNew);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPPLAYLIST_H__B739DAEE_6828_4128_8A0A_E6750502339C__INCLUDED_)

diff --git a/plugins/wmpa/wmpplaylistarray.cpp b/plugins/wmpa/wmpplaylistarray.cpp
new file mode 100644
index 00000000..8baf1a87
--- /dev/null
+++ b/plugins/wmpa/wmpplaylistarray.cpp
@@ -0,0 +1,35 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpplaylistarray.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpplaylist.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistArray properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistArray operations

+

+long CWMPPlaylistArray::GetCount()

+{

+	long result;

+	InvokeHelper(0x1f5, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CWMPPlaylist CWMPPlaylistArray::Item(long lIndex)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x1f6, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		lIndex);

+	return CWMPPlaylist(pDispatch);

+}

diff --git a/plugins/wmpa/wmpplaylistarray.h b/plugins/wmpa/wmpplaylistarray.h
new file mode 100644
index 00000000..9299b42c
--- /dev/null
+++ b/plugins/wmpa/wmpplaylistarray.h
@@ -0,0 +1,38 @@
+#if !defined(AFX_WMPPLAYLISTARRAY_H__6368C8A4_18CF_4937_993F_F7FBE512B851__INCLUDED_)

+#define AFX_WMPPLAYLISTARRAY_H__6368C8A4_18CF_4937_993F_F7FBE512B851__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPPlaylist;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistArray wrapper class

+

+class CWMPPlaylistArray : public COleDispatchDriver

+{

+public:

+	CWMPPlaylistArray() {}		// Calls COleDispatchDriver default constructor

+	CWMPPlaylistArray(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPPlaylistArray(const CWMPPlaylistArray& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetCount();

+	CWMPPlaylist Item(long lIndex);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPPLAYLISTARRAY_H__6368C8A4_18CF_4937_993F_F7FBE512B851__INCLUDED_)

diff --git a/plugins/wmpa/wmpplaylistcollection.cpp b/plugins/wmpa/wmpplaylistcollection.cpp
new file mode 100644
index 00000000..f13c98de
--- /dev/null
+++ b/plugins/wmpa/wmpplaylistcollection.cpp
@@ -0,0 +1,82 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpplaylistcollection.h"

+

+// Dispatch interfaces referenced by this interface

+#include "wmpplaylist.h"

+#include "WMPPlaylistArray.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistCollection properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistCollection operations

+

+CWMPPlaylist CWMPPlaylistCollection::newPlaylist(LPCTSTR bstrName)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x228, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrName);

+	return CWMPPlaylist(pDispatch);

+}

+

+CWMPPlaylistArray CWMPPlaylistCollection::getAll()

+{

+	LPDISPATCH pDispatch;

+	InvokeHelper(0x229, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, NULL);

+	return CWMPPlaylistArray(pDispatch);

+}

+

+CWMPPlaylistArray CWMPPlaylistCollection::getByName(LPCTSTR bstrName)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x22a, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		bstrName);

+	return CWMPPlaylistArray(pDispatch);

+}

+

+void CWMPPlaylistCollection::remove(LPDISPATCH pItem)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x22c, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pItem);

+}

+

+void CWMPPlaylistCollection::setDeleted(LPDISPATCH pItem, BOOL varfIsDeleted)

+{

+	static BYTE parms[] =

+		VTS_DISPATCH VTS_BOOL;

+	InvokeHelper(0x230, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 pItem, varfIsDeleted);

+}

+

+BOOL CWMPPlaylistCollection::isDeleted(LPDISPATCH pItem)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x231, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		pItem);

+	return result;

+}

+

+CWMPPlaylist CWMPPlaylistCollection::importPlaylist(LPDISPATCH pItem)

+{

+	LPDISPATCH pDispatch;

+	static BYTE parms[] =

+		VTS_DISPATCH;

+	InvokeHelper(0x232, DISPATCH_METHOD, VT_DISPATCH, (void*)&pDispatch, parms,

+		pItem);

+	return CWMPPlaylist(pDispatch);

+}

diff --git a/plugins/wmpa/wmpplaylistcollection.h b/plugins/wmpa/wmpplaylistcollection.h
new file mode 100644
index 00000000..b18d95ce
--- /dev/null
+++ b/plugins/wmpa/wmpplaylistcollection.h
@@ -0,0 +1,44 @@
+#if !defined(AFX_WMPPLAYLISTCOLLECTION_H__D07F4C6A_4574_4463_8A11_4A5654E38062__INCLUDED_)

+#define AFX_WMPPLAYLISTCOLLECTION_H__D07F4C6A_4574_4463_8A11_4A5654E38062__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+// Dispatch interfaces referenced by this interface

+class CWMPPlaylist;

+class CWMPPlaylistArray;

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPPlaylistCollection wrapper class

+

+class CWMPPlaylistCollection : public COleDispatchDriver

+{

+public:

+	CWMPPlaylistCollection() {}		// Calls COleDispatchDriver default constructor

+	CWMPPlaylistCollection(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPPlaylistCollection(const CWMPPlaylistCollection& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	CWMPPlaylist newPlaylist(LPCTSTR bstrName);

+	CWMPPlaylistArray getAll();

+	CWMPPlaylistArray getByName(LPCTSTR bstrName);

+	void remove(LPDISPATCH pItem);

+	void setDeleted(LPDISPATCH pItem, BOOL varfIsDeleted);

+	BOOL isDeleted(LPDISPATCH pItem);

+	CWMPPlaylist importPlaylist(LPDISPATCH pItem);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPPLAYLISTCOLLECTION_H__D07F4C6A_4574_4463_8A11_4A5654E38062__INCLUDED_)

diff --git a/plugins/wmpa/wmpsettings.cpp b/plugins/wmpa/wmpsettings.cpp
new file mode 100644
index 00000000..662a336a
--- /dev/null
+++ b/plugins/wmpa/wmpsettings.cpp
@@ -0,0 +1,193 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpsettings.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPSettings properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPSettings operations

+

+BOOL CWMPSettings::GetIsAvailable(LPCTSTR bstrItem)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x71, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,

+		bstrItem);

+	return result;

+}

+

+BOOL CWMPSettings::GetAutoStart()

+{

+	BOOL result;

+	InvokeHelper(0x65, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetAutoStart(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x65, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+CString CWMPSettings::GetBaseURL()

+{

+	CString result;

+	InvokeHelper(0x6c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetBaseURL(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x6c, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+CString CWMPSettings::GetDefaultFrame()

+{

+	CString result;

+	InvokeHelper(0x6d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetDefaultFrame(LPCTSTR lpszNewValue)

+{

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x6d, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 lpszNewValue);

+}

+

+BOOL CWMPSettings::GetInvokeURLs()

+{

+	BOOL result;

+	InvokeHelper(0x67, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetInvokeURLs(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x67, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+BOOL CWMPSettings::GetMute()

+{

+	BOOL result;

+	InvokeHelper(0x68, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetMute(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x68, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

+

+long CWMPSettings::GetPlayCount()

+{

+	long result;

+	InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetPlayCount(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+double CWMPSettings::GetRate()

+{

+	double result;

+	InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_R8, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetRate(double newValue)

+{

+	static BYTE parms[] =

+		VTS_R8;

+	InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 newValue);

+}

+

+long CWMPSettings::GetBalance()

+{

+	long result;

+	InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetBalance(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+long CWMPSettings::GetVolume()

+{

+	long result;

+	InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetVolume(long nNewValue)

+{

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 nNewValue);

+}

+

+BOOL CWMPSettings::getMode(LPCTSTR bstrMode)

+{

+	BOOL result;

+	static BYTE parms[] =

+		VTS_BSTR;

+	InvokeHelper(0x6e, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,

+		bstrMode);

+	return result;

+}

+

+void CWMPSettings::setMode(LPCTSTR bstrMode, BOOL varfMode)

+{

+	static BYTE parms[] =

+		VTS_BSTR VTS_BOOL;

+	InvokeHelper(0x6f, DISPATCH_METHOD, VT_EMPTY, NULL, parms,

+		 bstrMode, varfMode);

+}

+

+BOOL CWMPSettings::GetEnableErrorDialogs()

+{

+	BOOL result;

+	InvokeHelper(0x70, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);

+	return result;

+}

+

+void CWMPSettings::SetEnableErrorDialogs(BOOL bNewValue)

+{

+	static BYTE parms[] =

+		VTS_BOOL;

+	InvokeHelper(0x70, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,

+		 bNewValue);

+}

diff --git a/plugins/wmpa/wmpsettings.h b/plugins/wmpa/wmpsettings.h
new file mode 100644
index 00000000..423f7e6d
--- /dev/null
+++ b/plugins/wmpa/wmpsettings.h
@@ -0,0 +1,55 @@
+#if !defined(AFX_WMPSETTINGS_H__28D3DCCC_3E9A_48AE_97A9_3C1337309AF4__INCLUDED_)

+#define AFX_WMPSETTINGS_H__28D3DCCC_3E9A_48AE_97A9_3C1337309AF4__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPSettings wrapper class

+

+class CWMPSettings : public COleDispatchDriver

+{

+public:

+	CWMPSettings() {}		// Calls COleDispatchDriver default constructor

+	CWMPSettings(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPSettings(const CWMPSettings& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	BOOL GetIsAvailable(LPCTSTR bstrItem);

+	BOOL GetAutoStart();

+	void SetAutoStart(BOOL bNewValue);

+	CString GetBaseURL();

+	void SetBaseURL(LPCTSTR lpszNewValue);

+	CString GetDefaultFrame();

+	void SetDefaultFrame(LPCTSTR lpszNewValue);

+	BOOL GetInvokeURLs();

+	void SetInvokeURLs(BOOL bNewValue);

+	BOOL GetMute();

+	void SetMute(BOOL bNewValue);

+	long GetPlayCount();

+	void SetPlayCount(long nNewValue);

+	double GetRate();

+	void SetRate(double newValue);

+	long GetBalance();

+	void SetBalance(long nNewValue);

+	long GetVolume();

+	void SetVolume(long nNewValue);

+	BOOL getMode(LPCTSTR bstrMode);

+	void setMode(LPCTSTR bstrMode, BOOL varfMode);

+	BOOL GetEnableErrorDialogs();

+	void SetEnableErrorDialogs(BOOL bNewValue);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPSETTINGS_H__28D3DCCC_3E9A_48AE_97A9_3C1337309AF4__INCLUDED_)

diff --git a/plugins/wmpa/wmpstringcollection.cpp b/plugins/wmpa/wmpstringcollection.cpp
new file mode 100644
index 00000000..a36d4d9c
--- /dev/null
+++ b/plugins/wmpa/wmpstringcollection.cpp
@@ -0,0 +1,32 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+

+#include "stdafx.h"

+#include "wmpstringcollection.h"

+

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPStringCollection properties

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPStringCollection operations

+

+long CWMPStringCollection::GetCount()

+{

+	long result;

+	InvokeHelper(0x191, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);

+	return result;

+}

+

+CString CWMPStringCollection::Item(long lIndex)

+{

+	CString result;

+	static BYTE parms[] =

+		VTS_I4;

+	InvokeHelper(0x192, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,

+		lIndex);

+	return result;

+}

diff --git a/plugins/wmpa/wmpstringcollection.h b/plugins/wmpa/wmpstringcollection.h
new file mode 100644
index 00000000..bc03db89
--- /dev/null
+++ b/plugins/wmpa/wmpstringcollection.h
@@ -0,0 +1,34 @@
+#if !defined(AFX_WMPSTRINGCOLLECTION_H__782BAE9B_652B_476D_9448_808027B17262__INCLUDED_)

+#define AFX_WMPSTRINGCOLLECTION_H__782BAE9B_652B_476D_9448_808027B17262__INCLUDED_

+

+#if _MSC_VER > 1000

+#pragma once

+#endif // _MSC_VER > 1000

+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

+

+// NOTE: Do not modify the contents of this file.  If this class is regenerated by

+//  Microsoft Visual C++, your modifications will be overwritten.

+

+/////////////////////////////////////////////////////////////////////////////

+// CWMPStringCollection wrapper class

+

+class CWMPStringCollection : public COleDispatchDriver

+{

+public:

+	CWMPStringCollection() {}		// Calls COleDispatchDriver default constructor

+	CWMPStringCollection(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

+	CWMPStringCollection(const CWMPStringCollection& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

+

+// Attributes

+public:

+

+// Operations

+public:

+	long GetCount();

+	CString Item(long lIndex);

+};

+

+//{{AFX_INSERT_LOCATION}}

+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

+

+#endif // !defined(AFX_WMPSTRINGCOLLECTION_H__782BAE9B_652B_476D_9448_808027B17262__INCLUDED_)

diff --git a/plugins/wmpa/xchat-plugin.cpp b/plugins/wmpa/xchat-plugin.cpp
new file mode 100644
index 00000000..c5634064
--- /dev/null
+++ b/plugins/wmpa/xchat-plugin.cpp
@@ -0,0 +1,590 @@
+/******************************************************************
+* $Id$
+*
+* $Log$
+*
+* Copyright © 2005 David Cullen, All rights reserved
+*
+******************************************************************/
+#include "stdafx.h"
+#include "xchat-plugin.h"
+#include <windows.h>
+#include <tchar.h>
+#include "wmpa.h"
+#include "WMPADialog.h"
+
+#define XMMS_SESSION 0
+
+/******************************************************************
+* Globalss
+******************************************************************/
+xchat_plugin *ph = NULL;
+CWMPPlayer4 *wmp;
+static const char subKey[] = "Software\\FlowerSoft\\WMPA";
+
+/******************************************************************
+* xchat_plugin_init
+******************************************************************/
+int xchat_plugin_init(xchat_plugin *plugin_handle,
+                      char **plugin_name,
+                      char **plugin_desc,
+                      char **plugin_version,
+                      char *arg)
+{
+   BOOL success;
+
+   ph = plugin_handle;
+
+   *plugin_name = "WMPA";
+   *plugin_desc = "Announce the current song from Windows Media Player.";
+   *plugin_version = VER_STRING;
+
+   // Show the song browser
+   success = StartWindowsMediaPlayer();
+   if (!success) {
+      xchat_printf(ph, "WMPA: Failed to show the song browser.");
+      xchat_printf(ph, "WMPA: Could not load plug-in version %s.", VER_STRING);
+      return(E_FAIL);
+   }
+
+   // Get a pointer to the Windows Media Player control
+   wmp = GetWindowsMediaPlayer();
+   if (wmp == NULL) {
+      xchat_printf(ph, "WMPA: Failed to get a pointer to the Windows Media Player interface.");
+      xchat_printf(ph, "WMPA: Could not load plug-in version %s.", VER_STRING);
+      return(E_POINTER);
+   }
+
+   // Restore the settings (need wmp first)
+   success = wmpaRestoreSettings();
+   if (!success) {
+      xchat_printf(ph, "WMPA: Failed to restore the settings.");
+   }
+
+   xchat_hook_command(ph, "auto", XCHAT_PRI_NORM, wmpaAuto, 0, 0);
+   xchat_hook_command(ph, "curr", XCHAT_PRI_NORM, wmpaCurr, 0, 0);
+   xchat_hook_command(ph, "find", XCHAT_PRI_NORM, wmpaFind, 0, 0);
+   xchat_hook_command(ph, "slist", XCHAT_PRI_NORM, wmpaList, 0, 0);
+   xchat_hook_command(ph, "next", XCHAT_PRI_NORM, wmpaNext, 0, 0);
+   xchat_hook_command(ph, "play", XCHAT_PRI_NORM, wmpaPlay, 0, 0);
+   xchat_hook_command(ph, "pause", XCHAT_PRI_NORM, wmpaPause, 0, 0);
+   xchat_hook_command(ph, "prev", XCHAT_PRI_NORM, wmpaPrev, 0, 0);
+   xchat_hook_command(ph, "song", XCHAT_PRI_NORM, wmpaSong, 0, 0);
+   xchat_hook_command(ph, "stop", XCHAT_PRI_NORM, wmpaStop, 0, 0);
+   xchat_hook_command(ph, "volume", XCHAT_PRI_NORM, wmpaVolume, 0, 0);
+   xchat_hook_command(ph, "wmpahelp", XCHAT_PRI_NORM, wmpaHelp, 0, 0);
+
+   xchat_printf(ph, "WMPA %s successfully loaded.", VER_STRING);
+   wmpaCommands();
+   xchat_printf(ph, "WMPA: e-mail me if you find any bugs: dcullen@intergate.com");
+
+   return 1;
+}
+
+/******************************************************************
+* xchat_plugin_deinit
+******************************************************************/
+int xchat_plugin_deinit(void)
+{
+   BOOL success;
+
+   xchat_printf(ph, "WMPA %s is unloading.", VER_STRING);
+
+   // Save the settings
+   success = wmpaSaveSettings();
+   if (!success) {
+      xchat_printf(ph, "WMPA: Failed to save the settings.");
+   }
+
+   wmp = NULL;
+
+   BOOL result = StopWindowsMediaPlayer();
+   if (!result) {
+      xchat_printf(ph, "WMPA could not shut down Windows Media Player.");
+   }
+
+   xchat_printf(ph, "WMPA %s has unloaded.", VER_STRING);
+   return 1;
+}
+
+/******************************************************************
+* xchat_plugin_get_info
+******************************************************************/
+void xchat_plugin_get_info(char **name, char **desc, char **version, void **reserved)
+{
+   *name = "WMPA";
+   *desc = "Announce the current song from Windows Media Player.";
+   *version = VER_STRING;
+   if (reserved) *reserved = NULL;
+}
+
+/******************************************************************
+* wmpaCommands
+******************************************************************/
+void wmpaCommands(void)
+{
+   xchat_printf(ph, "WMPA: /auto [on/off]   : Turn on/off auto announce of the current song or display the current setting");
+   xchat_printf(ph, "WMPA: /curr            : Tell what song is currently playing");
+   xchat_printf(ph, "WMPA: /find [word]     : Find songs with \"word\" in their title, create a new playlist, and play it");
+   xchat_printf(ph, "WMPA: /slist [word]    : List songs with \"word\" in their title");
+   xchat_printf(ph, "WMPA: /next            : Play the next song");
+   xchat_printf(ph, "WMPA: /play            : Play the current song");
+   xchat_printf(ph, "WMPA: /pause           : Pause the current song");
+   xchat_printf(ph, "WMPA: /prev            : Play the previous song");
+   xchat_printf(ph, "WMPA: /song            : Announce the current song from Windows Media Player in xchat");
+   xchat_printf(ph, "WMPA: /stop            : Stop the current song");
+   xchat_printf(ph, "WMPA: /volume [volume] : Set the volume (0 to 100) or display the current volume");
+   xchat_printf(ph, "WMPA: /wmpahelp        : Display this help.");
+}
+
+/******************************************************************
+* wmpaAuto
+******************************************************************/
+int wmpaAuto(char *word[], char *word_eol[], void *user_data)
+{
+   CWMPADialog *pDialog;
+   char *state;
+
+   pDialog = GetWMPADialog();
+   if (pDialog == NULL) return(XCHAT_EAT_ALL);
+
+   if (CString(word[2]).IsEmpty()) {
+      if (pDialog->autoAnnounce) {
+         state = "on";
+      }
+      else {
+         state = "off";
+      }
+   }
+   else {
+      state = word[2];
+      if (CString(state) == "on") {
+         pDialog->autoAnnounce = TRUE;
+      }
+      if (CString(state) == "off") {
+         pDialog->autoAnnounce = FALSE;
+      }
+      wmpaSaveSettings();
+   }
+
+   xchat_printf(ph, "WMPA: auto is %s", state);
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaCurr
+******************************************************************/
+int wmpaCurr(char *word[], char *word_eol[], void *user_data)
+{
+   xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaFind
+******************************************************************/
+int wmpaFind(char *word[], char *word_eol[], void *user_data)
+{
+   long index;
+   long count;
+   long found;
+
+   if (wmp != NULL) {
+      CWMPMediaCollection mc = wmp->GetMediaCollection();
+      CWMPPlaylist all = mc.getAll();
+      CWMPPlaylistCollection pc = wmp->GetPlaylistCollection();
+      CWMPPlaylistArray pa = pc.getAll();
+      CWMPPlaylist playlist;
+      CWMPMedia media;
+
+      for (index = 0; index < pc.getAll().GetCount(); index++) {
+         if (pc.getAll().Item(index).GetName() == CString(word_eol[2])) {
+            playlist = pc.getAll().Item(index);
+            pc.remove(playlist);
+         }
+      }
+
+      playlist = pc.newPlaylist(word_eol[2]);
+
+      count = all.GetCount();
+      found = 0;
+      for (index = 0; index < count; index++) {
+         media = all.GetItem(index);
+         CString artist = media.getItemInfo("Artist");
+         CString title  = media.getItemInfo("Title");
+         CString album  = media.getItemInfo("Album");
+         if ( (artist.Find(word_eol[2]) != -1) ||
+              (title.Find(word_eol[2])  != -1) ||
+              (album.Find(word_eol[2])  != -1) ) {
+            playlist.appendItem(media);
+            found++;
+         }
+      }
+
+      if (found > 0) {
+         xchat_printf(ph, "WMPA: Found %d songs with \"%s\" in them", found, word_eol[2]);
+         wmp->SetCurrentPlaylist(playlist);
+         wmp->GetControls().play();
+         xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());
+
+         CWMPADialog *dialog = GetWMPADialog();
+         if (dialog != NULL) {
+            dialog->UpdateSongList();
+            dialog->SelectCurrentSong();
+            dialog->UpdatePlayLists();
+         }
+
+      }
+      else {
+         xchat_printf(ph, "WMPA: Could not find %s", word_eol[2]);
+      }
+
+   }
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaList
+******************************************************************/
+int wmpaList(char *word[], char *word_eol[], void *user_data)
+{
+   long index;
+   long count;
+   long found;
+
+   if (wmp != NULL) {
+      xchat_printf(ph, "WMPA: Listing songs with \"%s\" in them", word_eol[2]);
+
+      CWMPMediaCollection mc = wmp->GetMediaCollection();
+      CWMPPlaylist all = mc.getAll();
+      CWMPMedia media;
+
+      count = all.GetCount();
+      found = 0;
+      for (index = 0; index < count; index++) {
+         media = all.GetItem(index);
+         CString artist = media.getItemInfo("Artist");
+         CString title  = media.getItemInfo("Title");
+         CString album  = media.getItemInfo("Album");
+         if ( (artist.Find(word_eol[2]) != -1) ||
+              (title.Find(word_eol[2])  != -1) ||
+              (album.Find(word_eol[2])  != -1) ) {
+            xchat_printf(ph, "WMPA: Found \"%s - %s (%s)\"", artist, title, album);
+            found++;
+         }
+      }
+
+      if (found > 0) {
+         if (found == 1)
+            xchat_printf(ph, "WMPA: Found %d song with \"%s\" in it", found, word_eol[2]);
+         else
+            xchat_printf(ph, "WMPA: Found %d songs with \"%s\" in them", found, word_eol[2]);
+      }
+      else {
+         xchat_printf(ph, "WMPA: Could not find any songs with \"%s\" in them", word_eol[2]);
+      }
+
+   }
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaNext
+******************************************************************/
+int wmpaNext(char *word[], char *word_eol[], void *user_data)
+{
+   if (wmp != NULL) {
+      wmp->GetControls().next();
+      xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());
+   }
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaPlay
+******************************************************************/
+int wmpaPlay(char *word[], char *word_eol[], void *user_data)
+{
+   if (wmp != NULL) {
+      wmp->GetControls().play();
+      xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());
+   }
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaPause
+******************************************************************/
+int wmpaPause(char *word[], char *word_eol[], void *user_data)
+{
+   if (wmp != NULL) {
+      wmp->GetControls().pause();
+      xchat_printf(ph, "WMPA: Pausing %s", (LPCTSTR) wmpaGetSongTitle());
+   }
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaPrev
+******************************************************************/
+int wmpaPrev(char *word[], char *word_eol[], void *user_data)
+{
+   if (wmp != NULL) {
+      wmp->GetControls().previous();
+      xchat_printf(ph, "WMPA: Playing %s", (LPCTSTR) wmpaGetSongTitle());
+   }
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaSong
+******************************************************************/
+int wmpaSong(char *word[], char *word_eol[], void *user_data)
+{
+   CString songTitle = wmpaGetSongTitle();
+
+   xchat_commandf(ph, "me is playing %s", (LPCTSTR) songTitle);
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaStop
+******************************************************************/
+int wmpaStop(char *word[], char *word_eol[], void *user_data)
+{
+   if (wmp != NULL) {
+      wmp->GetControls().stop();
+      xchat_printf(ph, "WMPA: Stopping %s", (LPCTSTR) wmpaGetSongTitle());
+   }
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaHelp
+******************************************************************/
+int wmpaHelp(char *word[], char *word_eol[], void *user_data)
+{
+   xchat_printf(ph, "\n");
+   xchat_printf(ph, "WMPA %s Help", VER_STRING);
+   wmpaCommands();
+   xchat_printf(ph, "\n");
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaVolume
+******************************************************************/
+int wmpaVolume(char *word[], char *word_eol[], void *user_data)
+{
+   char *endPtr;
+   long volume;
+
+   if (CString(word[2]).IsEmpty()) {
+      volume = wmp->GetSettings().GetVolume();
+   }
+   else {
+      volume = strtol(word[2], &endPtr, 10);
+
+      if ((wmp != NULL) && (volume >= 0) && (volume <= 100)) {
+         wmp->GetSettings().SetVolume(volume);
+         wmpaSaveSettings();
+      }
+   }
+
+   xchat_printf(ph, "WMPA: volume is %d", volume);
+
+   return(XCHAT_EAT_ALL);
+}
+
+/******************************************************************
+* wmpaRestoreSettings
+******************************************************************/
+BOOL wmpaRestoreSettings(void)
+{
+   CWMPADialog *pDialog;
+   DWORD type;
+   int volume;
+   BOOL autoAnnounce;
+   DWORD size;
+   BOOL result;
+
+   if (wmp == NULL) return(FALSE);
+
+   volume = 50;
+   result = GetSetting("Volume", &type, (LPBYTE) &volume, &size);
+   wmp->GetSettings().SetVolume(volume);
+
+   autoAnnounce = FALSE;
+   pDialog = GetWMPADialog();
+   if (pDialog != NULL) {
+      result = result && GetSetting("Auto", &type, (LPBYTE) &autoAnnounce, &size);
+      pDialog->autoAnnounce = autoAnnounce;
+   }
+   else {
+      result = FALSE;
+   }
+
+   return(result);
+}
+
+/******************************************************************
+* wmpaSaveSettings
+******************************************************************/
+BOOL wmpaSaveSettings(void)
+{
+   CWMPADialog *pDialog;
+   int volume;
+   BOOL autoAnnounce;
+   BOOL result;
+
+   if (wmp == NULL) return(FALSE);
+
+   volume = wmp->GetSettings().GetVolume();
+   result = SaveSetting("Volume", REG_DWORD, (CONST BYTE *) &volume, sizeof(volume));
+
+   pDialog = GetWMPADialog();
+   if (pDialog != NULL) {
+      autoAnnounce = pDialog->autoAnnounce;
+      result = result && SaveSetting("Auto", REG_DWORD, (CONST BYTE *) &autoAnnounce, sizeof(autoAnnounce));
+   }
+   else {
+      result = FALSE;
+   }
+
+   return(result);
+}
+
+/******************************************************************
+* wmpaGetSongTitle
+******************************************************************/
+CString wmpaGetSongTitle(void)
+{
+   char buffer[32];
+
+   if (wmp == NULL) return(CString());
+
+   CWMPMedia media      = wmp->GetCurrentMedia();
+   if (media == NULL) {
+      xchat_printf(ph, "WMPA: Could not get current media");
+      return(XCHAT_EAT_ALL);
+   }
+
+   CString artist       = media.getItemInfo("Artist");
+   CString title        = media.getItemInfo("Title");
+   CString album        = media.getItemInfo("Album");
+   CString bitrate      = media.getItemInfo("Bitrate");
+   CString duration     = media.GetDurationString();
+
+   long krate = strtoul((LPCTSTR) bitrate, NULL, 10) / 1000;
+   _ultoa(krate, buffer, 10);
+   bitrate = CString(buffer);
+
+   // Creatte the song title
+   CString songTitle("");
+   songTitle += artist;
+   if (songTitle.IsEmpty()) songTitle += "Various";
+   songTitle += " - ";
+   songTitle += title;
+   songTitle += " (";
+   songTitle += album;
+   songTitle += ") [";
+   songTitle += duration;
+   songTitle += "/";
+   songTitle += bitrate;
+   songTitle += "Kbps]";
+
+   return(songTitle);
+}
+
+/******************************************************************
+* SaveSetting
+******************************************************************/
+BOOL SaveSetting(LPCTSTR name, DWORD type, CONST BYTE *value, DWORD size)
+{
+   HKEY hKey;
+   DWORD disposition;
+   LONG result;
+
+   if (wmp == NULL) return(FALSE);
+   if (name == NULL) return(FALSE);
+
+   result = RegOpenKeyEx(HKEY_CURRENT_USER,
+                         subKey,
+                         0,
+                         KEY_WRITE,
+                         &hKey);
+
+   if (result != ERROR_SUCCESS) {
+      result = RegCreateKeyEx(HKEY_CURRENT_USER,
+                              subKey,
+                              0,
+                              NULL,
+                              REG_OPTION_NON_VOLATILE,
+                              KEY_WRITE,
+                              NULL,
+                              &hKey,
+                              &disposition);
+
+      if (result != ERROR_SUCCESS) return(FALSE);
+   }
+
+   result = RegSetValueEx(hKey,
+                          name,
+                          0,
+                          type,
+                          value,
+                          size);
+
+   if (result == ERROR_SUCCESS) {
+      RegCloseKey(hKey);
+      return(TRUE);
+   }
+
+   RegCloseKey(hKey);
+   return(FALSE);
+}
+
+/******************************************************************
+* GetSetting
+******************************************************************/
+BOOL GetSetting(LPCTSTR name, DWORD *type, LPBYTE value, DWORD *size)
+{
+   HKEY hKey;
+   LONG result;
+
+   if (wmp == NULL) return(FALSE);
+   if (type == NULL) return(FALSE);
+   if (value == NULL) return(FALSE);
+   if (size == NULL) return(FALSE);
+
+   result = RegOpenKeyEx(HKEY_CURRENT_USER,
+                         subKey,
+                         0,
+                         KEY_READ,
+                         &hKey);
+
+   if (result != ERROR_SUCCESS) return(FALSE);
+
+   result = RegQueryValueEx(hKey,
+                            name,
+                            0,
+                            type,
+                            value,
+                            size);
+
+   RegCloseKey(hKey);
+
+   if (result == ERROR_SUCCESS) {
+      return(TRUE);
+   }
+
+   RegCloseKey(hKey);
+   return(FALSE);
+}
+
diff --git a/plugins/wmpa/xchat-plugin.h b/plugins/wmpa/xchat-plugin.h
new file mode 100644
index 00000000..ee189ffe
--- /dev/null
+++ b/plugins/wmpa/xchat-plugin.h
@@ -0,0 +1,368 @@
+/* You can distribute this header with your plugins for easy compilation */
+#ifndef XCHAT_PLUGIN_H
+#define XCHAT_PLUGIN_H
+
+#define VER_STRING _T("1.0.2 (BETA)")
+
+#include "stdafx.h"
+#include <windows.h>
+#include <time.h>
+#include <tchar.h>
+
+#define XCHAT_IFACE_MAJOR     1
+#define XCHAT_IFACE_MINOR     9
+#define XCHAT_IFACE_MICRO     11
+#define XCHAT_IFACE_VERSION   ((XCHAT_IFACE_MAJOR * 10000) + \
+                              (XCHAT_IFACE_MINOR * 100) + \
+                              (XCHAT_IFACE_MICRO))
+
+#define XCHAT_PRI_HIGHEST  127
+#define XCHAT_PRI_HIGH     64
+#define XCHAT_PRI_NORM     0
+#define XCHAT_PRI_LOW      (-64)
+#define XCHAT_PRI_LOWEST   (-128)
+
+#define XCHAT_FD_READ      1
+#define XCHAT_FD_WRITE     2
+#define XCHAT_FD_EXCEPTION 4
+#define XCHAT_FD_NOTSOCKET 8
+
+#define XCHAT_EAT_NONE     0                                   /* pass it on through! */
+#define XCHAT_EAT_XCHAT    1                                   /* don't let xchat see this event */
+#define XCHAT_EAT_PLUGIN   2                                   /* don't let other plugins see this event */
+#define XCHAT_EAT_ALL      (XCHAT_EAT_XCHAT|XCHAT_EAT_PLUGIN)  /* don't let anything see this event */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+   typedef struct _xchat_plugin xchat_plugin;
+   typedef struct _xchat_list xchat_list;
+   typedef struct _xchat_hook xchat_hook;
+#ifndef PLUGIN_C
+   typedef struct _xchat_context xchat_context;
+#endif
+
+#ifndef PLUGIN_C
+   struct _xchat_plugin {
+      /* these are only used on win32 */
+      xchat_hook *(*xchat_hook_command) (xchat_plugin *ph,
+                                         const char *name,
+                                         int pri,
+                                         int (*callback) (char *word[], char *word_eol[], void *user_data),
+                                         const char *help_text,
+                                         void *userdata);
+      xchat_hook *(*xchat_hook_server) (xchat_plugin *ph,
+                                        const char *name,
+                                        int pri,
+                                        int (*callback) (char *word[], char *word_eol[], void *user_data),
+                                        void *userdata);
+      xchat_hook *(*xchat_hook_print) (xchat_plugin *ph,
+                                       const char *name,
+                                       int pri,
+                                       int (*callback) (char *word[], void *user_data),
+                                       void *userdata);
+      xchat_hook *(*xchat_hook_timer) (xchat_plugin *ph,
+                                       int timeout,
+                                       int (*callback) (void *user_data),
+                                       void *userdata);
+      xchat_hook *(*xchat_hook_fd) (xchat_plugin *ph,
+                                    int fd,
+                                    int flags,
+                                    int (*callback) (int fd, int flags, void *user_data),
+                                    void *userdata);
+      void *(*xchat_unhook) (xchat_plugin *ph,
+                             xchat_hook *hook);
+      void (*xchat_print) (xchat_plugin *ph,
+                           const char *text);
+      void (*xchat_printf) (xchat_plugin *ph,
+                            const char *format, ...);
+      void (*xchat_command) (xchat_plugin *ph,
+                             const char *command);
+      void (*xchat_commandf) (xchat_plugin *ph,
+                              const char *format, ...);
+      int (*xchat_nickcmp) (xchat_plugin *ph,
+                            const char *s1,
+                            const char *s2);
+      int (*xchat_set_context) (xchat_plugin *ph,
+                                xchat_context *ctx);
+      xchat_context *(*xchat_find_context) (xchat_plugin *ph,
+                                            const char *servname,
+                                            const char *channel);
+      xchat_context *(*xchat_get_context) (xchat_plugin *ph);
+      const char *(*xchat_get_info) (xchat_plugin *ph,
+                                     const char *id);
+      int (*xchat_get_prefs) (xchat_plugin *ph,
+                              const char *name,
+                              const char **string,
+                              int *integer);
+      xchat_list * (*xchat_list_get) (xchat_plugin *ph,
+                                      const char *name);
+      void (*xchat_list_free) (xchat_plugin *ph,
+                               xchat_list *xlist);
+      const char * const * (*xchat_list_fields) (xchat_plugin *ph,
+                                                 const char *name);
+      int (*xchat_list_next) (xchat_plugin *ph,
+                              xchat_list *xlist);
+      const char * (*xchat_list_str) (xchat_plugin *ph,
+                                      xchat_list *xlist,
+                                      const char *name);
+      int (*xchat_list_int) (xchat_plugin *ph,
+                             xchat_list *xlist,
+                             const char *name);
+      void * (*xchat_plugingui_add) (xchat_plugin *ph,
+                                     const char *filename,
+                                     const char *name,
+                                     const char *desc,
+                                     const char *version,
+                                     char *reserved);
+      void (*xchat_plugingui_remove) (xchat_plugin *ph,
+                                      void *handle);
+      int (*xchat_emit_print) (xchat_plugin *ph,
+                               const char *event_name, ...);
+      int (*xchat_read_fd) (xchat_plugin *ph,
+                            void *src,
+                            char *buf,
+                            int *len);
+      time_t (*xchat_list_time) (xchat_plugin *ph,
+                                 xchat_list *xlist,
+                                 const char *name);
+      char *(*xchat_gettext) (xchat_plugin *ph,
+                              const char *msgid);
+      void (*xchat_send_modes) (xchat_plugin *ph,
+                                const char **targets,
+                                int ntargets,
+                                int modes_per_line,
+                                char sign,
+                                char mode);
+      char *(*xchat_strip) (xchat_plugin *ph,
+                            const char *str,
+                            int len,
+                            int flags);
+      void (*xchat_free) (xchat_plugin *ph,
+                          void *ptr);
+   };
+#endif
+
+
+   xchat_hook *
+   xchat_hook_command (xchat_plugin *ph,
+                       const char *name,
+                       int pri,
+                       int (*callback) (char *word[], char *word_eol[], void *user_data),
+                       const char *help_text,
+                       void *userdata);
+
+   xchat_hook *
+   xchat_hook_server (xchat_plugin *ph,
+                      const char *name,
+                      int pri,
+                      int (*callback) (char *word[], char *word_eol[], void *user_data),
+                      void *userdata);
+
+   xchat_hook *
+   xchat_hook_print (xchat_plugin *ph,
+                     const char *name,
+                     int pri,
+                     int (*callback) (char *word[], void *user_data),
+                     void *userdata);
+
+   xchat_hook *
+   xchat_hook_timer (xchat_plugin *ph,
+                     int timeout,
+                     int (*callback) (void *user_data),
+                     void *userdata);
+
+   xchat_hook *
+   xchat_hook_fd (xchat_plugin *ph,
+                  int fd,
+                  int flags,
+                  int (*callback) (int fd, int flags, void *user_data),
+                  void *userdata);
+
+   void *
+   xchat_unhook (xchat_plugin *ph,
+                 xchat_hook *hook);
+
+   void
+   xchat_print (xchat_plugin *ph,
+                const char *text);
+
+   void
+   xchat_printf (xchat_plugin *ph,
+                 const char *format, ...);
+
+   void
+   xchat_command (xchat_plugin *ph,
+                  const char *command);
+
+   void
+   xchat_commandf (xchat_plugin *ph,
+                   const char *format, ...);
+
+   int
+   xchat_nickcmp (xchat_plugin *ph,
+                  const char *s1,
+                  const char *s2);
+
+   int
+   xchat_set_context (xchat_plugin *ph,
+                      xchat_context *ctx);
+
+   xchat_context *
+   xchat_find_context (xchat_plugin *ph,
+                       const char *servname,
+                       const char *channel);
+
+   xchat_context *
+   xchat_get_context (xchat_plugin *ph);
+
+   const char *
+   xchat_get_info (xchat_plugin *ph,
+                   const char *id);
+
+   int
+   xchat_get_prefs (xchat_plugin *ph,
+                    const char *name,
+                    const char **string,
+                    int *integer);
+
+   xchat_list *
+   xchat_list_get (xchat_plugin *ph,
+                   const char *name);
+
+   void
+   xchat_list_free (xchat_plugin *ph,
+                    xchat_list *xlist);
+
+   const char * const *
+   xchat_list_fields (xchat_plugin *ph,
+                      const char *name);
+
+   int
+   xchat_list_next (xchat_plugin *ph,
+                    xchat_list *xlist);
+
+   const char *
+   xchat_list_str (xchat_plugin *ph,
+                   xchat_list *xlist,
+                   const char *name);
+
+   int
+   xchat_list_int (xchat_plugin *ph,
+                   xchat_list *xlist,
+                   const char *name);
+
+   time_t
+   xchat_list_time (xchat_plugin *ph,
+                    xchat_list *xlist,
+                    const char *name);
+
+   void *
+   xchat_plugingui_add (xchat_plugin *ph,
+                        const char *filename,
+                        const char *name,
+                        const char *desc,
+                        const char *version,
+                        char *reserved);
+
+   void
+   xchat_plugingui_remove (xchat_plugin *ph,
+                           void *handle);
+
+   int
+   xchat_emit_print (xchat_plugin *ph,
+                     const char *event_name, ...);
+
+   char *
+   xchat_gettext (xchat_plugin *ph,
+                  const char *msgid);
+
+   void
+   xchat_send_modes (xchat_plugin *ph,
+                     const char **targets,
+                     int ntargets,
+                     int modes_per_line,
+                     char sign,
+                     char mode);
+
+   char *
+   xchat_strip (xchat_plugin *ph,
+                const char *str,
+                int len,
+                int flags);
+
+   void
+   xchat_free (xchat_plugin *ph,
+               void *ptr);
+
+#if !defined(PLUGIN_C) && defined(WIN32)
+#ifndef XCHAT_PLUGIN_HANDLE
+#define XCHAT_PLUGIN_HANDLE (ph)
+#endif
+#define xchat_hook_command ((XCHAT_PLUGIN_HANDLE)->xchat_hook_command)
+#define xchat_hook_server ((XCHAT_PLUGIN_HANDLE)->xchat_hook_server)
+#define xchat_hook_print ((XCHAT_PLUGIN_HANDLE)->xchat_hook_print)
+#define xchat_hook_timer ((XCHAT_PLUGIN_HANDLE)->xchat_hook_timer)
+#define xchat_hook_fd ((XCHAT_PLUGIN_HANDLE)->xchat_hook_fd)
+#define xchat_unhook ((XCHAT_PLUGIN_HANDLE)->xchat_unhook)
+#define xchat_print ((XCHAT_PLUGIN_HANDLE)->xchat_print)
+#define xchat_printf ((XCHAT_PLUGIN_HANDLE)->xchat_printf)
+#define xchat_command ((XCHAT_PLUGIN_HANDLE)->xchat_command)
+#define xchat_commandf ((XCHAT_PLUGIN_HANDLE)->xchat_commandf)
+#define xchat_nickcmp ((XCHAT_PLUGIN_HANDLE)->xchat_nickcmp)
+#define xchat_set_context ((XCHAT_PLUGIN_HANDLE)->xchat_set_context)
+#define xchat_find_context ((XCHAT_PLUGIN_HANDLE)->xchat_find_context)
+#define xchat_get_context ((XCHAT_PLUGIN_HANDLE)->xchat_get_context)
+#define xchat_get_info ((XCHAT_PLUGIN_HANDLE)->xchat_get_info)
+#define xchat_get_prefs ((XCHAT_PLUGIN_HANDLE)->xchat_get_prefs)
+#define xchat_list_get ((XCHAT_PLUGIN_HANDLE)->xchat_list_get)
+#define xchat_list_free ((XCHAT_PLUGIN_HANDLE)->xchat_list_free)
+#define xchat_list_fields ((XCHAT_PLUGIN_HANDLE)->xchat_list_fields)
+#define xchat_list_str ((XCHAT_PLUGIN_HANDLE)->xchat_list_str)
+#define xchat_list_int ((XCHAT_PLUGIN_HANDLE)->xchat_list_int)
+#define xchat_list_time ((XCHAT_PLUGIN_HANDLE)->xchat_list_time)
+#define xchat_list_next ((XCHAT_PLUGIN_HANDLE)->xchat_list_next)
+#define xchat_plugingui_add ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_add)
+#define xchat_plugingui_remove ((XCHAT_PLUGIN_HANDLE)->xchat_plugingui_remove)
+#define xchat_emit_print ((XCHAT_PLUGIN_HANDLE)->xchat_emit_print)
+#define xchat_gettext ((XCHAT_PLUGIN_HANDLE)->xchat_gettext)
+#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)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/******************************************************************
+* Globals
+******************************************************************/
+extern xchat_plugin *ph;
+
+/******************************************************************
+* Prototypes
+******************************************************************/
+void wmpaCommands(void);
+int wmpaAuto(char *word[], char *word_eol[], void *user_data);
+int wmpaCurr(char *word[], char *word_eol[], void *user_data);
+int wmpaFind(char *word[], char *word_eol[], void *user_data);
+int wmpaList(char *word[], char *word_eol[], void *user_data);
+int wmpaNext(char *word[], char *word_eol[], void *user_data);
+int wmpaPlay(char *word[], char *word_eol[], void *user_data);
+int wmpaPause(char *word[], char *word_eol[], void *user_data);
+int wmpaPrev(char *word[], char *word_eol[], void *user_data);
+int wmpaSong(char *word[], char *word_eol[], void *user_data);
+int wmpaStop(char *word[], char *word_eol[], void *user_data);
+int wmpaVolume(char *word[], char *word_eol[], void *user_data);
+int wmpaHelp(char *word[], char *word_eol[], void *user_data);
+BOOL wmpaRestoreSettings(void);
+BOOL wmpaSaveSettings(void);
+CString wmpaGetSongTitle(void);
+BOOL SaveSetting(LPCTSTR name, DWORD type, CONST BYTE *value, DWORD size);
+BOOL GetSetting(LPCTSTR name, DWORD *type, LPBYTE value, DWORD *size);
+
+#endif /* XCHAT_PLUGIN_H */
+
diff --git a/plugins/xchat-plugin.h b/plugins/xchat-plugin.h
index 30b19295..1b7da8fb 100644
--- a/plugins/xchat-plugin.h
+++ b/plugins/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/plugins/xdcc/makefile.mak b/plugins/xdcc/makefile.mak
new file mode 100644
index 00000000..0a12347e
--- /dev/null
+++ b/plugins/xdcc/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: xdcc.obj xdcc.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcxdcc.dll /def:xdcc.def xdcc.obj

+

+xdcc.def:

+	echo EXPORTS > xdcc.def

+	echo xchat_plugin_init >> xdcc.def

+	echo xchat_plugin_deinit >> xdcc.def

+

+xdcc.obj: xdcc.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. xdcc.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/xdcc/xdcc.c b/plugins/xdcc/xdcc.c
index 147a3c33..060dbbe3 100644
--- a/plugins/xdcc/xdcc.c
+++ b/plugins/xdcc/xdcc.c
@@ -2,11 +2,15 @@
 
 #include <glib.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
 #include "xchat-plugin.h"
+#include "../../src/common/xchat.h"
 
 static xchat_plugin *ph;	/* plugin handle */
 
diff --git a/plugins/xsasl/makefile.mak b/plugins/xsasl/makefile.mak
new file mode 100644
index 00000000..e1ffd0ec
--- /dev/null
+++ b/plugins/xsasl/makefile.mak
@@ -0,0 +1,18 @@
+include "..\..\src\makeinc.mak"

+

+all: xsasl.obj xsasl.def

+	link $(LDFLAGS) $(LIBS) /dll /out:xcxsasl.dll /def:xsasl.def xsasl.obj

+

+xsasl.def:

+	echo EXPORTS > xsasl.def

+	echo xchat_plugin_init >> xsasl.def

+	echo xchat_plugin_deinit >> xsasl.def

+

+xsasl.obj: xsasl.c makefile.mak

+	cl $(CFLAGS) $(GLIB) /I.. xsasl.c

+

+clean:

+	del *.obj

+	del *.dll

+	del *.exp

+	del *.lib

diff --git a/plugins/xsasl/xsasl.c b/plugins/xsasl/xsasl.c
new file mode 100644
index 00000000..8abce20b
--- /dev/null
+++ b/plugins/xsasl/xsasl.c
@@ -0,0 +1,314 @@
+/* XChat-WDK
+ * Copyright (c) 2010 <ygrek@autistici.org>
+ * Copyright (c) 2012 Berke Viktor.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * SASL authentication plugin for XChat
+ * Extremely primitive: only PLAIN, no error checking
+ *
+ * http://ygrek.org.ua/p/cap_sasl.html
+ *
+ * Docs:
+ *  http://hg.atheme.org/charybdis/charybdis/file/6144f52a119b/doc/sasl.txt
+ *  http://tools.ietf.org/html/rfc4422
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib/gbase64.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+static const char name[] = "X-SASL";
+static const char desc[] = "SASL authentication plugin for XChat";
+static const char version[] = "1.1";
+static const char xsasl_help[] = "X-SASL Usage:\n /XSASL ADD <login> <password> <network>, enable/update SASL authentication for given network\n /XSASL DEL <network>, disable SASL authentication for given network\n /XSASL LIST, get the list of SASL-enabled networks\n";
+
+struct sasl_info
+{
+	char const* login;
+	char const* password;
+	char const* network;
+};
+
+typedef struct sasl_info sasl_info;
+
+static int
+add_info (char const* login, char const* password, char const* network)
+{
+	char buffer[512];
+
+	sprintf (buffer, "%s:%s", login, password);
+	return xchat_pluginpref_set_str (ph, network, buffer);
+}
+
+static int
+del_info (char const* network)
+{
+	return xchat_pluginpref_delete (ph, network);
+}
+
+static void
+print_info ()
+{
+	char list[512];
+	char* token;
+
+	if (xchat_pluginpref_list (ph, list))
+	{
+		xchat_printf (ph, "%s\tSASL-enabled networks:", name);
+		xchat_printf (ph, "%s\t----------------------", name);
+		token = strtok (list, ",");
+		while (token != NULL)
+		{
+			xchat_printf (ph, "%s\t%s", name, token);
+			token = strtok (NULL, ",");
+		}
+	}
+	else
+	{
+		xchat_printf (ph, "%s\tThere are no SASL-enabled networks currently", name);
+	}
+}
+
+static sasl_info*
+find_info (char const* network)
+{
+	char buffer[512];
+	char* token;
+	sasl_info* cur = (sasl_info*) malloc (sizeof (sasl_info));
+
+	if (xchat_pluginpref_get_str (ph, network, buffer))
+	{
+		token = strtok (buffer, ":");
+		cur->login = g_strdup (token);
+		token = strtok (NULL, ":");
+		cur->password = g_strdup (token);
+		cur->network = g_strdup (network);
+
+		return cur;
+	}
+
+	return NULL;
+}
+
+static sasl_info*
+get_info (void)
+{
+	const char* name;
+	name = xchat_get_info (ph, "network");
+
+	if (name)
+	{
+		return find_info (name);
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+static int
+authend_cb (char *word[], char *word_eol[], void *userdata)
+{
+	if (get_info ())
+	{
+		/* omit cryptic server message parts */
+		xchat_printf (ph, "%s\t%s\n", name, ++word_eol[4]);
+		xchat_commandf (ph, "QUOTE CAP END");
+	}
+
+	return XCHAT_EAT_ALL;
+}
+
+/*
+static int
+disconnect_cb (char *word[], void *userdata)
+{
+	xchat_printf (ph, "disconnected\n");
+	return XCHAT_EAT_NONE;
+}
+*/
+
+static int
+server_cb (char *word[], char *word_eol[], void *userdata)
+{
+	size_t len;
+	char* buf;
+	char* enc;
+	sasl_info* p;
+
+	if (strcmp ("AUTHENTICATE", word[1]) == 0 && strcmp ("+", word[2]) == 0)
+	{
+		p = get_info ();
+
+		if (!p)
+		{
+			return XCHAT_EAT_NONE;
+		}
+
+		xchat_printf (ph, "%s\tAuthenticating as %s\n", name, p->login);
+
+		len = strlen (p->login) * 2 + 2 + strlen (p->password);
+		buf = (char*) malloc (len + 1);
+		strcpy (buf, p->login);
+		strcpy (buf + strlen (p->login) + 1, p->login);
+		strcpy (buf + strlen (p->login) * 2 + 2, p->password);
+		enc = g_base64_encode ((unsigned char*) buf, len);
+
+		/* xchat_printf (ph, "AUTHENTICATE %s\}", enc); */
+		xchat_commandf (ph, "QUOTE AUTHENTICATE %s", enc);
+
+		free (enc);
+		free (buf);
+
+		return XCHAT_EAT_ALL;
+	}
+
+	return XCHAT_EAT_NONE;
+}
+
+static int
+cap_cb (char *word[], char *word_eol[], void *userdata)
+{
+	if (get_info ())
+	{
+		/* FIXME test sasl cap */
+		/* this is visible in the rawlog in case someone needs it, otherwise it's just noise */
+		/* xchat_printf (ph, "%s\t%s\n", name, word_eol[1]); */
+		xchat_commandf (ph, "QUOTE AUTHENTICATE PLAIN");
+	}
+
+	return XCHAT_EAT_ALL;
+}
+
+static int
+sasl_cmd_cb (char *word[], char *word_eol[], void *userdata)
+{
+	const char* login;
+	const char* password;
+	const char* network;
+	const char* mode = word[2];
+
+	if (!stricmp ("ADD", mode))
+	{
+		login = word[3];
+		password = word[4];
+		network = word_eol[5];
+
+		if (!network || !*network)	/* only check for the last word, if it's there, the previous ones will be there, too */
+		{
+			xchat_printf (ph, "%s", xsasl_help);
+			return XCHAT_EAT_ALL;
+		}
+
+		if (add_info (login, password, network))
+		{
+			xchat_printf (ph, "%s\tEnabled SASL authentication for the \"%s\" network\n", name, network);
+		}
+		else
+		{
+			xchat_printf (ph, "%s\tFailed to enable SASL authentication for the \"%s\" network\n", name, network);
+		}
+
+		return XCHAT_EAT_ALL;
+	}
+	else if (!stricmp ("DEL", mode))
+	{
+		network = word_eol[3];
+
+		if (!network || !*network)
+		{
+			xchat_printf (ph, "%s", xsasl_help);
+			return XCHAT_EAT_ALL;
+		}
+
+		if (del_info (network))
+		{
+			xchat_printf (ph, "%s\tDisabled SASL authentication for the \"%s\" network\n", name, network);
+		}
+		else
+		{
+			xchat_printf (ph, "%s\tFailed to disable SASL authentication for the \"%s\" network\n", name, network);
+		}
+
+		return XCHAT_EAT_ALL;
+	}
+	else if (!stricmp ("LIST", mode))
+	{
+		print_info ();
+		return XCHAT_EAT_ALL;
+	}
+	else
+	{
+		xchat_printf (ph, "%s", xsasl_help);
+		return XCHAT_EAT_ALL;
+	}
+}
+
+static int
+connect_cb (char *word[], void *userdata)
+{
+	if (get_info ())
+	{
+		xchat_printf (ph, "%s\tSASL enabled\n", name);
+		xchat_commandf (ph, "QUOTE CAP REQ :sasl");
+	}
+
+	return XCHAT_EAT_NONE;
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	/* we need to save this for use with any xchat_* functions */
+	ph = plugin_handle;
+
+	/* tell xchat our info */
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	xchat_hook_command (ph, "XSASL", XCHAT_PRI_NORM, sasl_cmd_cb, xsasl_help, 0);
+	xchat_hook_print (ph, "Connected", XCHAT_PRI_NORM, connect_cb, NULL);
+	/* xchat_hook_print (ph, "Disconnected", XCHAT_PRI_NORM, disconnect_cb, NULL); */
+	xchat_hook_server (ph, "CAP", XCHAT_PRI_NORM, cap_cb, NULL);
+	xchat_hook_server (ph, "RAW LINE", XCHAT_PRI_NORM, server_cb, NULL);
+	xchat_hook_server (ph, "903", XCHAT_PRI_NORM, authend_cb, NULL);
+	xchat_hook_server (ph, "904", XCHAT_PRI_NORM, authend_cb, NULL);
+	xchat_hook_server (ph, "905", XCHAT_PRI_NORM, authend_cb, NULL);
+	xchat_hook_server (ph, "906", XCHAT_PRI_NORM, authend_cb, NULL);
+	xchat_hook_server (ph, "907", XCHAT_PRI_NORM, authend_cb, NULL);
+
+	xchat_printf (ph, "%s plugin loaded\n", name);
+
+	return 1;
+}
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}
diff --git a/plugins/xtray/bitmaps/sd.bmp b/plugins/xtray/bitmaps/sd.bmp
new file mode 100644
index 00000000..9d6b7f95
--- /dev/null
+++ b/plugins/xtray/bitmaps/sd.bmp
Binary files differdiff --git a/plugins/xtray/callbacks.cpp b/plugins/xtray/callbacks.cpp
new file mode 100644
index 00000000..1b7f452f
--- /dev/null
+++ b/plugins/xtray/callbacks.cpp
@@ -0,0 +1,734 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#define _WIN32_IE 0x0601

+

+#include <windows.h>

+#include <stdio.h>

+#include <commctrl.h>

+#include <tchar.h>

+

+#include "xchat-plugin.h"

+#include "utility.h"

+#include "xtray.h"

+#include "xchat.h"

+#include "callbacks.h"

+#include "resource.h"

+#include "sdTray.h"

+#include "sdAlerts.h"

+

+HWND	g_hPrefTabEvents;

+HWND	g_hPrefTabSettings;

+HWND	g_hPrefTabAlerts;

+HWND	g_hPrefTabAbout;

+bool	g_bCanQuit;

+int		g_iIsActive = 1;

+

+

+BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)

+{

+	TCHAR szTitle[10];

+	GetWindowText(hWnd, szTitle, 9);

+

+	if(_tcsstr(szTitle, _T("XChat [")))

+	{

+		g_hXchatWnd = hWnd;

+		return false;

+	}

+	

+	return true;

+}

+

+/***********************************************************************************************/

+/******* our xchat event call back, get the name and info for each event and save it ***********/

+/******* for our alerts later														***********/

+/***********************************************************************************************/

+int event_cb(char *word[], void *userdata)

+{

+	int iEvent = (int)userdata;

+

+	if(iEvent > 10 && iEvent != 21)

+		return XCHAT_EAT_NONE;

+

+	/***************************************************************************************/

+	/***** if the window is minimized or if we're allowed to show alerts when its not	 **/

+	/***** and if the option to show the specified alert is true and if we're even		**/

+	/***** allowed to show alerts at all then we show them (a bit confusing but it works) **/

+	/***************************************************************************************/

+	if(((g_iIsActive == 0) || !(g_dwPrefs & (1<<PREF_OSBWM))) && (g_dwPrefs & (1<<PREF_AMAE)) && (g_dwPrefs & (1<<iEvent)))

+	{	

+		/*********************************/

+		/*********** Our Buffers *********/

+		/*********************************/

+		char			szInfo[512];

+		char			szName[64];

+		DWORD			dwInfoFlags;

+		int iTime		= g_iTime*1000;

+		char *szTemp	= NULL;

+

+		if(g_dwPrefs & (1<<PREF_KAOI))

+		{

+			iTime = 0;

+		}

+

+		switch(iEvent)

+		{

+		case CHAN_HILIGHT:

+			_snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]);

+			_snprintf(szName, 64, "Highlight: %s", xchat_get_info (ph, "channel"));

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case CHAN_MESSAGE:

+			_snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]);

+			_snprintf(szName, 64, "Channel Message: %s", xchat_get_info (ph, "channel"));

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case CHAN_TOPIC_CHANGE:

+			_snprintf(szInfo, 512, "%s has changed the topic to %s", word[1], word[2]);

+			_snprintf(szName, 64, "Topic Change: %s", word[3]);

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case CHAN_INVITE:

+			_snprintf(szInfo, 512, "%s has invited you into %s", word[1], word[2]);

+			_snprintf(szName, 64, "Invite");

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case CHAN_KICKED:

+			_snprintf(szInfo, 512, "Kicked from %s by %s:\r\n%s", word[2], word[3], word[4]);

+			_snprintf(szName, 64, "Kick");

+			dwInfoFlags = NIIF_WARNING;

+			break;

+		case CHAN_BANNED:

+			_snprintf(szInfo, 512, "Cannot join #%s You are banned.", word[1]);

+			_snprintf(szName, 64, "Banned");

+			dwInfoFlags = NIIF_WARNING;

+			break;

+		case CTCP_GENERIC:

+			_snprintf(szInfo, 512, "%s:\r\nCTCP %s", word[2], word[1]);

+			_snprintf(szName, 64, "CTCP");

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case PMSG_RECEIVE:

+			_snprintf(szInfo, 512, "%s:\r\n%s", word[1], word[2]);

+			_snprintf(szName, 64, "Private Message");

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case SERV_DISCONNECT:

+			_snprintf(szInfo, 512, "Disconnected\r\nError: %s", word[1]);

+			_snprintf(szName, 64, "Disconnect");

+			dwInfoFlags = NIIF_ERROR;

+			break;

+		case SERV_KILLED:

+			_snprintf(szInfo, 512, "Killed(%s(%s))", word[1], word[2]);

+			_snprintf(szName, 64, "Server Admin has killed you");

+			dwInfoFlags = NIIF_ERROR;

+			break;

+		case SERV_NOTICE:

+			_snprintf(szInfo, 512, "Notice:\r\n%s: %s", word[1], word[2]);

+			_snprintf(szName, 64, "Notice");

+			dwInfoFlags = NIIF_INFO;

+			break;

+		case 11:

+			_snprintf(szInfo, 512, ":\r\n%s: %s", word[1], word[2]);

+			_snprintf(szName, 64, "Notice");

+			dwInfoFlags = NIIF_INFO;

+			break;

+		}

+

+		/**************************************************************************************/

+		/***** Use windows instead of balloons, and if its a window should we keep it open ****/

+		/***** indefinately?															   ****/

+		/**************************************************************************************/

+		szTemp = xchat_strip_color(szInfo);

+

+		if(g_dwPrefs & (1<<PREF_UWIOB))

+		{

+			sdSystemAlert((HINSTANCE)g_hInstance, IDD_ALERT, szTemp, szName, iTime);

+		}

+		else

+		{

+			ShowBalloon(g_hXchatWnd, 1, szTemp, szName, iTime, dwInfoFlags);

+		}

+

+		free(szTemp);

+	}

+

+	if(g_dwPrefs & (1<<PREF_BLINK) && (g_dwPrefs & (1<<iEvent)))

+	{

+		BlinkIcon(g_hXchatWnd, 1, g_hIcons[0], g_hIcons[(iEvent+1)], 700, 5);

+	}

+

+	/***********************************/

+	/***** pass the events to xchat ****/

+	/***********************************/

+	return XCHAT_EAT_NONE;

+}

+

+int command_cb(char *word[], char *word_eol[], void *userdata)

+{

+	char szInfo[512];

+	char *szTemp	= NULL;

+	int iTime		= g_iTime*1000;

+

+	_snprintf(szInfo, 512, word_eol[2]);

+	szTemp = xchat_strip_color(szInfo);

+

+	if(g_dwPrefs & (1<<PREF_KAOI))

+	{

+		iTime = 0;

+	}

+

+	if(((g_iIsActive == 0) || !(g_dwPrefs & (1<<PREF_OSBWM))) && (g_dwPrefs & (1<<PREF_AMAE)))

+	{

+		if(g_dwPrefs & (1<<PREF_UWIOB))

+		{

+			sdSystemAlert((HINSTANCE)g_hInstance, IDD_ALERT, szTemp, "Alert", iTime);

+		}

+		else

+		{

+			ShowBalloon(g_hXchatWnd, 1, szTemp, "Alert", iTime, NIIF_INFO);

+		}

+	}

+

+	free(szTemp);

+

+	return XCHAT_EAT_ALL;

+}

+

+LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	switch(msg)

+	{

+	case WM_CLOSE:

+		{

+			if((g_dwPrefs & (1<<PREF_MIOC)) && (g_bCanQuit == false))

+			{

+				/*******************************************/

+				/**** to autoaway or not to autoaway...  ***/

+				/*******************************************/

+				if(g_dwPrefs & (1<<PREF_AOM))

+				{

+					xchat_globally_away(g_szAway);

+				}

+

+				/**************************************************/

+				/**** Win32 API call to hide the window and	     **/

+				/**** save the fact that its minimized for later **/

+				/**************************************************/

+				g_iIsActive = 0;

+				ShowWindow(hWnd, SW_HIDE);

+

+				return 0;

+			}

+			else

+			{

+				if(g_hPrefDlg != NULL)

+				{

+					DestroyWindow(g_hPrefDlg);

+				}

+

+				StopBlink(hWnd, 1, g_hIcons[0]);

+				

+				if(sdAlertNum())

+				{

+					sdCloseAlerts();

+					HoldClose();

+					return 0;

+				}

+			}

+		}

+		break;

+	case WM_SIZE:

+		{

+			/******************************************/

+			/***** User wants to minimize xChat, ******/

+			/***** are we allowed to go to tray? ******/

+			/******************************************/

+			if((g_dwPrefs & (1<<PREF_TOT)) && (wparam == SIZE_MINIMIZED))

+			{

+				/*******************************************/

+				/**** to autoaway or not to autoaway...  ***/

+				/*******************************************/

+				if(g_dwPrefs & (1<<PREF_AOM))

+				{

+					xchat_globally_away(g_szAway);

+				}

+

+				/**************************************************/

+				/**** Win32 API call to hide the window and	     **/

+				/**** save the fact that its minimized for later **/

+				/**************************************************/

+				g_iIsActive = 0;

+				ShowWindow(hWnd, SW_HIDE);

+			}

+		}

+		break;

+	/**********************************/

+	/*** user clicked the tray icon ***/

+	/**********************************/

+	case WM_TRAYMSG:

+		{

+			switch(lparam)

+			{

+			case WM_LBUTTONDOWN:

+				{

+					if(!g_iIsActive)

+					{

+						/*********************************************************/

+						/*** 0: its hiden, restore it and show it, if autoaway ***/

+						/*** is on, set us as back							 ***/

+						/*********************************************************/

+						SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);

+						SetForegroundWindow(hWnd);

+						g_iIsActive = 1;

+

+						if(g_dwPrefs & (1<<PREF_AOM))

+						{

+							xchat_globally_back();

+						}

+					}

+					else

+					{

+						SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);

+					}

+				}

+				break;

+			case WM_RBUTTONDOWN:

+				{

+					/******************************************/

+					/*** user wants to see the menu find out **/

+					/*** where the mouse is and show it	  **/

+					/******************************************/

+					POINT pt;

+					int iRet;

+

+					GetCursorPos(&pt);

+					SetForegroundWindow(hWnd);

+

+					ModifyMenu(g_hTrayMenu, 2, (MF_POPUP | MF_BYPOSITION), (UINT)setServerMenu(), _T("Away"));

+

+					Sleep(175);

+

+					iRet = TrackPopupMenuEx(g_hTrayMenu, (TPM_RETURNCMD | TPM_LEFTALIGN), pt.x, pt.y, hWnd, NULL);

+

+					/***********************************/

+					/*** nRet is the users selection, **/

+					/*** process it				   **/

+					/***********************************/

+					sdTrayProc(hWnd, iRet);

+				}

+				break;

+			}

+		}

+		break;

+	default:

+		{

+			/*****************************************************/

+			/*** the taskbar has been restarted, re-add our icon */

+			/*****************************************************/

+			if(msg == RegisterWindowMessage(_T("TaskbarCreated")))

+			{

+				char szVersion[64];

+				_snprintf(szVersion, 64, "XChat-WDK [%s]", xchat_get_info(ph, "version"));

+				AddIcon(g_hXchatWnd, 1, g_hIcons[0], szVersion, (NIF_ICON | NIF_MESSAGE | NIF_TIP), WM_TRAYMSG);

+			}

+		}

+		break;

+	}

+

+	return CallWindowProc(g_hOldProc, hWnd, msg, wparam, lparam);

+}

+

+/****************************************************/

+/*** process messages from the tray menu ************/

+/****************************************************/

+LRESULT CALLBACK sdTrayProc(HWND hWnd, int msg)

+{

+	switch(msg)

+	{

+	case ACT_EXIT:

+		{

+			g_bCanQuit = true;

+			PostMessage(hWnd, WM_CLOSE, 0, 0);

+		}

+		break;

+	case ACT_RESTORE:

+		{

+			/***********************************************/

+			/** user wants us to restore the xchat window **/

+			/** and of autoaway is on, set as back		**/

+			/***********************************************/

+			SendMessage(g_hXchatWnd, WM_SYSCOMMAND, SC_RESTORE, 0);

+			SetForegroundWindow(hWnd);

+			

+			if((!g_iIsActive) && (g_dwPrefs & (1<<PREF_AOM)))

+			{

+				xchat_globally_back();

+				g_iIsActive = 1;

+			}

+		}

+		break;

+	case ACT_SETTINGS:

+		{

+			ShowWindow(g_hPrefDlg, SW_SHOW);

+		}

+		break;

+	case ACT_AWAY:

+		{

+			xchat_globally_away(g_szAway);

+		}

+		break;

+	case ACT_BACK:

+		{

+			xchat_globally_back();

+		}

+		break;

+	default:

+		{

+			if(msg > 0)

+			{

+				xchat_set_context(ph, xchat_find_server(msg-1));

+

+				if(!xchat_get_info(ph, "away"))

+				{

+					xchat_away(g_szAway);

+				}

+				else

+				{

+					xchat_back();

+				}

+			}

+		}

+		break;

+	}

+

+	return 1;

+}

+

+int CALLBACK PrefProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	switch(msg)

+	{

+	case WM_INITDIALOG:

+		{

+			TCITEM tci1;

+			TCITEM tci2;

+			TCITEM tci3;

+			TCITEM tci4;

+

+			tci1.mask		= TCIF_TEXT;

+			tci1.pszText	= _T("Settings");

+			tci1.cchTextMax	= strlen("Settings");

+			SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 0, (LPARAM)&tci1);

+

+			tci2.mask		= TCIF_TEXT;

+			tci2.pszText	= _T("Alerts");

+			tci2.cchTextMax	= strlen("Alerts");

+			SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 1, (LPARAM)&tci2);

+

+			tci3.mask		= TCIF_TEXT;

+			tci3.pszText	= _T("Events");

+			tci3.cchTextMax	= strlen("Events");

+			SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 2, (LPARAM)&tci3);

+

+			tci4.mask		= TCIF_TEXT;

+			tci4.pszText	= _T("About");

+			tci4.cchTextMax	= strlen("About");

+			SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_INSERTITEM, 3, (LPARAM)&tci4);

+

+

+			/***********************************************************************************/

+			/***********************************************************************************/

+			/***********************************************************************************/

+

+			g_hPrefTabSettings	= CreateDialog((HINSTANCE)g_hInstance,

+									MAKEINTRESOURCE(IDD_SETTINGS),

+									hWnd,		

+									(DLGPROC)SettingsProc);

+			SetDialog(g_hPrefTabSettings,	IDD_SETTINGS);

+

+			g_hPrefTabAlerts	= CreateDialog((HINSTANCE)g_hInstance,

+									MAKEINTRESOURCE(IDD_ALERTS),

+									hWnd,

+									(DLGPROC)AlertsProc);

+			SetDialog(g_hPrefTabAlerts,		IDD_ALERTS);

+

+			g_hPrefTabEvents	= CreateDialog((HINSTANCE)g_hInstance,

+									MAKEINTRESOURCE(IDD_EVENTS),

+									hWnd,		

+									(DLGPROC)EventsProc);

+			SetDialog(g_hPrefTabEvents,		IDD_EVENTS);

+

+			g_hPrefTabAbout		= CreateDialog((HINSTANCE)g_hInstance,

+									MAKEINTRESOURCE(IDD_ABOUT),

+									hWnd,

+									(DLGPROC)AboutProc);

+		}

+		break;

+	case WM_SHOWWINDOW:

+		{

+			if(wparam)

+			{

+				SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_SETCURSEL, 0, 0);

+				ShowWindow(g_hPrefTabSettings,	SW_SHOW);

+				ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+				ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+				ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+			}

+		}

+		break;

+	case WM_NOTIFY:

+		{

+			NMHDR *pData = (NMHDR *)lparam;

+

+			switch(pData->code)

+			{

+			case TCN_SELCHANGE:

+				{

+					switch(SendDlgItemMessage(hWnd, IDC_TAB_CONTROL, TCM_GETCURSEL, 0, 0))

+					{

+					case 0:

+						{

+							ShowWindow(g_hPrefTabSettings,	SW_SHOW);

+							ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+							ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+							ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+						}

+						break;

+					case 1:

+						{

+							ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+							ShowWindow(g_hPrefTabAlerts,	SW_SHOW);

+							ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+							ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+						}

+						break;

+					case 2:

+						{

+							ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+							ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+							ShowWindow(g_hPrefTabEvents,	SW_SHOW);

+							ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+						}

+						break;

+					case 3:

+						{

+							ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+							ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+							ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+							ShowWindow(g_hPrefTabAbout,		SW_SHOW);

+						}

+						break;

+					}

+				}

+				break;

+			}

+		}

+		break;

+	case WM_CLOSE:

+		{

+			ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+			ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+			ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+			ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+			ShowWindow(hWnd,				SW_HIDE);

+			return TRUE;

+		}

+		break;

+	case WM_COMMAND:

+		{

+			switch(wparam)

+			{

+			case IDC_PREF_OK:

+				{

+					CheckPrefs(g_hPrefTabEvents,	IDD_EVENTS);

+					CheckPrefs(g_hPrefTabSettings,	IDD_SETTINGS);

+					CheckPrefs(g_hPrefTabAlerts,	IDD_ALERTS);

+

+					SavePrefs(0);

+

+					ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+					ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+					ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+					ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+					ShowWindow(hWnd,				SW_HIDE);

+					return TRUE;

+				}

+				break;

+			case IDC_PREF_CANCEL:

+				{

+					ShowWindow(g_hPrefTabEvents,	SW_HIDE);

+					ShowWindow(g_hPrefTabSettings,	SW_HIDE);

+					ShowWindow(g_hPrefTabAlerts,	SW_HIDE);

+					ShowWindow(g_hPrefTabAbout,		SW_HIDE);

+					ShowWindow(hWnd,				SW_HIDE);

+					return TRUE;

+				}

+				break;

+			case IDC_PREF_APPLY:

+				{

+					CheckPrefs(g_hPrefTabEvents,	IDD_EVENTS);

+					CheckPrefs(g_hPrefTabSettings,	IDD_SETTINGS);

+					CheckPrefs(g_hPrefTabAlerts,	IDD_ALERTS);

+

+					SavePrefs(0);

+					return FALSE;

+				}

+				break;

+			}

+		}

+		break;

+	case WM_DESTROY:

+		{

+			SendMessage(g_hPrefTabEvents,	WM_CLOSE, 0, 0);

+			SendMessage(g_hPrefTabSettings,	WM_CLOSE, 0, 0);

+			SendMessage(g_hPrefTabAbout,	WM_CLOSE, 0, 0);

+			SendMessage(g_hPrefTabAlerts,	WM_CLOSE, 0, 0);

+		}

+		break;

+	}

+

+	return FALSE;

+}

+

+/****************************************************/

+/****************************************************/

+/****************************************************/

+LRESULT CALLBACK AlertsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	switch(msg)

+	{

+	case WM_CLOSE:

+		{

+			DestroyWindow(hWnd);

+			return TRUE;

+			break;

+		}

+		break;

+	case WM_COMMAND:

+		{

+			switch(LOWORD(wparam))

+			{

+			case PREF_AMAE:

+				{

+					SetToggle(hWnd, PREF_OSBWM,			PREF_AMAE, TRUE);

+					SetToggle(hWnd, PREF_UWIOB,			PREF_AMAE, TRUE);

+					SetToggle(hWnd, PREF_KAOI,			PREF_AMAE, TRUE);

+					

+					if(IsDlgButtonChecked(hWnd, PREF_AMAE))

+					{

+						SetToggle(hWnd, IDC_ALERT_HOTKEY,		PREF_UWIOB, TRUE);

+						SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT,	PREF_UWIOB, TRUE);

+						SetToggle(hWnd, IDC_ALERT_TIME,			PREF_KAOI, FALSE);

+						SetToggle(hWnd, IDC_ALERT_TIME_TEXT,	PREF_KAOI, FALSE);

+					}

+					else

+					{

+						SetToggle(hWnd, IDC_ALERT_HOTKEY,		PREF_AMAE, TRUE);

+						SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT,	PREF_AMAE, TRUE);

+						SetToggle(hWnd, IDC_ALERT_TIME,			PREF_AMAE, TRUE);

+						SetToggle(hWnd, IDC_ALERT_TIME_TEXT,	PREF_AMAE, TRUE);

+					}

+				}

+				break;

+			case PREF_UWIOB:

+				{

+					SetToggle(hWnd, IDC_ALERT_HOTKEY,		PREF_UWIOB, TRUE);

+					SetToggle(hWnd, IDC_ALERT_HOTKEY_TEXT,	PREF_UWIOB, TRUE);

+				}

+				break;

+			case PREF_KAOI:

+				{

+					SetToggle(hWnd, IDC_ALERT_TIME,			PREF_KAOI, FALSE);

+					SetToggle(hWnd, IDC_ALERT_TIME_TEXT,	PREF_KAOI, FALSE);

+				}

+				break;

+			}

+			break;

+		}

+	}

+

+	return FALSE;

+}

+

+/****************************************************/

+/****************************************************/

+/****************************************************/

+LRESULT CALLBACK AboutProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	if(msg == WM_CLOSE)

+	{

+		DestroyWindow(hWnd);

+		return true;

+	}

+

+	return FALSE;

+}

+

+/*****************************************************/

+/** Process the events for our event dialog **********/

+/*****************************************************/

+LRESULT CALLBACK EventsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	if(msg == WM_CLOSE)

+	{

+		DestroyWindow(hWnd);

+		return true;

+	}

+

+	return FALSE;

+}

+

+/*****************************************************/

+/** Process the events for our settings dialog this **/

+/** is alot more complicated because options are	**/

+/** enabled/disabled based on the state of others   **/

+/*****************************************************/

+LRESULT CALLBACK SettingsProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	if(msg == WM_CLOSE)

+	{

+		DestroyWindow(hWnd);

+		return true;

+	}

+

+	return FALSE;

+}

+

+/*****************************************************/

+/** this is the hotkey message  processing function **/

+/** this window is always open and ready to be told **/

+/** if someone has hit the hotkey, if they did, we  **/

+/** need to close out all of the tray alerts, for   **/

+/** this I wrote sdCloseAlerts, more info there	 **/

+/*****************************************************/

+LRESULT CALLBACK HotKeyProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	if(msg == WM_CLOSE)

+	{

+		DestroyWindow(hWnd);

+		return true;

+	}

+	else if(msg == WM_HOTKEY)

+	{

+		sdCloseAlerts();

+	}

+

+	return FALSE;

+}

+

diff --git a/plugins/xtray/callbacks.h b/plugins/xtray/callbacks.h
new file mode 100644
index 00000000..99cbae74
--- /dev/null
+++ b/plugins/xtray/callbacks.h
@@ -0,0 +1,37 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _H_CALLBACKS_H

+#define _H_CALLBACKS_H

+

+int					event_cb		(char *word[], void *userdata);

+int					command_cb		(char *word[], char *word_eol[], void *userdata);

+

+LRESULT CALLBACK	WindowProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+BOOL	CALLBACK	EnumWindowsProc	(HWND hWnd, LPARAM lParam);

+LRESULT CALLBACK	sdTrayProc		(HWND hwnd, int msg);

+

+LRESULT CALLBACK	AlertProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+LRESULT CALLBACK	HotKeyProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+LRESULT CALLBACK	EventsProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+LRESULT CALLBACK	AboutProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+LRESULT CALLBACK	AlertsProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+LRESULT CALLBACK	SettingsProc	(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+int		CALLBACK	PrefProc		(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

+

+#endif
\ No newline at end of file
diff --git a/plugins/xtray/icons/banned.ico b/plugins/xtray/icons/banned.ico
new file mode 100644
index 00000000..fef8df8c
--- /dev/null
+++ b/plugins/xtray/icons/banned.ico
Binary files differdiff --git a/plugins/xtray/icons/chan_msg.ico b/plugins/xtray/icons/chan_msg.ico
new file mode 100644
index 00000000..793d050e
--- /dev/null
+++ b/plugins/xtray/icons/chan_msg.ico
Binary files differdiff --git a/plugins/xtray/icons/disconnected.ico b/plugins/xtray/icons/disconnected.ico
new file mode 100644
index 00000000..9063e7e3
--- /dev/null
+++ b/plugins/xtray/icons/disconnected.ico
Binary files differdiff --git a/plugins/xtray/icons/highlight-1-3.ico b/plugins/xtray/icons/highlight-1-3.ico
new file mode 100644
index 00000000..a759145b
--- /dev/null
+++ b/plugins/xtray/icons/highlight-1-3.ico
Binary files differdiff --git a/plugins/xtray/icons/highlight.ico b/plugins/xtray/icons/highlight.ico
new file mode 100644
index 00000000..625cca9a
--- /dev/null
+++ b/plugins/xtray/icons/highlight.ico
Binary files differdiff --git a/plugins/xtray/icons/kicked.ico b/plugins/xtray/icons/kicked.ico
new file mode 100644
index 00000000..845a74e1
--- /dev/null
+++ b/plugins/xtray/icons/kicked.ico
Binary files differdiff --git a/plugins/xtray/icons/priv_msg-1-2-2.ico b/plugins/xtray/icons/priv_msg-1-2-2.ico
new file mode 100644
index 00000000..7941ff77
--- /dev/null
+++ b/plugins/xtray/icons/priv_msg-1-2-2.ico
Binary files differdiff --git a/plugins/xtray/icons/sd.ico b/plugins/xtray/icons/sd.ico
new file mode 100644
index 00000000..ca179621
--- /dev/null
+++ b/plugins/xtray/icons/sd.ico
Binary files differdiff --git a/plugins/xtray/icons/server_notice.ico b/plugins/xtray/icons/server_notice.ico
new file mode 100644
index 00000000..ff765d87
--- /dev/null
+++ b/plugins/xtray/icons/server_notice.ico
Binary files differdiff --git a/plugins/xtray/icons/xchat.ico b/plugins/xtray/icons/xchat.ico
new file mode 100644
index 00000000..73247fd0
--- /dev/null
+++ b/plugins/xtray/icons/xchat.ico
Binary files differdiff --git a/plugins/xtray/makefile.mak b/plugins/xtray/makefile.mak
new file mode 100644
index 00000000..ec2c94b3
--- /dev/null
+++ b/plugins/xtray/makefile.mak
@@ -0,0 +1,37 @@
+include "..\..\src\makeinc.mak"
+
+TARGET = xtray.dll
+
+TRAY_OBJECTS = \
+callbacks.obj \
+sdAlerts.obj \
+sdTray.obj \
+utility.obj \
+xchat.obj \
+xtray.obj
+
+CPPFLAGS = $(CPPFLAGS) /D_STL70_ /D_STATIC_CPPLIB /EHsc /DUNICODE /D_UNICODE
+
+all: $(TRAY_OBJECTS) $(TARGET)
+
+xtray.def:
+	echo EXPORTS > xtray.def
+	echo xchat_plugin_init >> xtray.def
+	echo xchat_plugin_deinit >> xtray.def
+
+.cpp.obj:
+	$(CC) $(CPPFLAGS) /I.. /c $<
+
+res:
+	rc /nologo resource.rc
+	
+$(TARGET): $(TRAY_OBJECTS) xtray.def res
+	$(LINK) /DLL /out:$(TARGET) $(LDFLAGS) $(TRAY_OBJECTS) ntstc_msvcrt.lib $(LIBS) /def:xtray.def resource.res
+
+clean:
+	del $(TARGET)
+	del *.obj
+	del xtray.def
+	del resource.res
+	del *.lib
+	del *.exp
diff --git a/plugins/xtray/resource.h b/plugins/xtray/resource.h
new file mode 100644
index 00000000..b8008c2c
--- /dev/null
+++ b/plugins/xtray/resource.h
@@ -0,0 +1,47 @@
+//{{NO_DEPENDENCIES}}

+// Microsoft Visual C++ generated include file.

+// Used by resource.rc

+//

+#define IDD_ALERTS                      104

+#define IDD_EVENTS                      105

+#define IDD_SETTINGS                    106

+#define IDD_ALERT                       107

+#define IDD_PREF                        108

+#define IDD_ABOUT                       109

+#define IDR_TRAY_MENU                   110

+#define ICO_XCHAT                       111

+#define ICO_BANNED                      112

+#define ICO_CHANMSG                     113

+#define ICO_DISCONNECTED                114

+#define ICO_HIGHLIGHT                   115

+#define ICO_KICKED                      116

+#define ICO_PMSG                        117

+#define ICO_SNOTICE                     118

+#define IDB_SD_LOGO                     119

+#define IDC_PREF_OK                     1014

+#define IDC_PREF_CANCEL                 1015

+#define IDC_PREF_APPLY                  1016

+#define IDC_AWAY_MSG                    1017

+#define IDC_ALERT_TIME                  1018

+#define IDC_TAB_CONTROL                 1019

+#define IDC_ALERT_HOTKEY                1020

+#define IDC_ALERT_MSG                   1021

+#define IDC_ALERT_HOTKEY_TEXT           1022

+#define IDC_ALERT_TIME_TEXT             1023

+#define ACT_EXIT                        40001

+#define ACT_SETTINGS                    40002

+#define ACT_AWAY                        40003

+#define ACT_BACK                        40004

+#define ACT_RESTORE                     40005

+#define IDC_STATIC                      -1

+

+// Next default values for new objects

+// 

+#ifdef APSTUDIO_INVOKED

+#ifndef APSTUDIO_READONLY_SYMBOLS

+#define _APS_NEXT_RESOURCE_VALUE        120

+#define _APS_NEXT_COMMAND_VALUE         40006

+#define _APS_NEXT_CONTROL_VALUE         1024

+#define _APS_NEXT_SYMED_VALUE           101

+#endif

+#endif

diff --git a/plugins/xtray/resource.rc b/plugins/xtray/resource.rc
new file mode 100644
index 00000000..312c74c4
--- /dev/null
+++ b/plugins/xtray/resource.rc
@@ -0,0 +1,309 @@
+// Microsoft Visual C++ generated resource script.

+//

+#include "resource.h"

+

+#define APSTUDIO_READONLY_SYMBOLS

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 2 resource.

+//

+#define APSTUDIO_HIDDEN_SYMBOLS

+#include "windows.h"

+#undef APSTUDIO_HIDDEN_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+#undef APSTUDIO_READONLY_SYMBOLS

+

+/////////////////////////////////////////////////////////////////////////////

+// English (U.S.) resources

+

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

+#ifdef _WIN32

+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

+#pragma code_page(1252)

+#endif //_WIN32

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Dialog

+//

+

+IDD_EVENTS DIALOGEX 8, 20, 216, 143

+STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CHILD

+FONT 8, "Tahoma", 0, 0, 0x0

+BEGIN

+    GROUPBOX        "XChat Events",IDC_STATIC,5,5,205,77

+    CONTROL         "Banned",4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,49,10

+    CONTROL         "Kicked",5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,32,49,10

+    CONTROL         "Killed",8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,49,10

+    CONTROL         "Disconnect",10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,60,49,10

+    CONTROL         "Private Message",7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,18,69,10

+    CONTROL         "Channel Message",21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,32,69,10

+    CONTROL         "Highlight",1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,46,69,10

+    CONTROL         "CTCP",6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,60,69,10

+    CONTROL         "Topic Change",3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,18,55,10

+    CONTROL         "Server Notice",9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,32,55,10

+    CONTROL         "Invite",2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,46,55,10

+END

+

+IDD_SETTINGS DIALOGEX 8, 20, 216, 143

+STYLE DS_SETFONT | WS_CHILD

+FONT 8, "Tahoma", 0, 0, 0x0

+BEGIN

+    GROUPBOX        "Options",IDC_STATIC,5,5,205,135

+    CONTROL         "Auto away on minimize",11,"Button",BS_AUTOCHECKBOX | 

+                    WS_TABSTOP,16,60,100,10

+    CONTROL         "Minimize XChat to the system tray",12,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,18,133,10

+    CONTROL         "Minimize to the tray instead of closing",17,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,32,174,9

+    EDITTEXT        IDC_AWAY_MSG,33,86,169,50,ES_AUTOHSCROLL

+    LTEXT           "Away Msg:",IDC_STATIC,27,72,35,8

+    CONTROL         "Remove XChat from the taskbar (only show in tray)",

+                    20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,191,9

+END

+

+IDD_ALERT DIALOGEX 0, 0, 151, 28

+STYLE DS_LOCALEDIT | DS_SETFONT | DS_NOIDLEMSG | DS_CENTER | WS_CAPTION | 

+    WS_SYSMENU

+EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW

+CAPTION "Event Name"

+FONT 8, "Tahoma", 0, 0, 0x1

+BEGIN

+    LTEXT           "Event Text",IDC_ALERT_MSG,3,0,147,27

+END

+

+IDD_PREF DIALOGEX 0, 0, 233, 190

+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | 

+    WS_SYSMENU

+CAPTION "X-Tray Preferences"

+FONT 8, "Tahoma", 0, 0, 0x0

+BEGIN

+    DEFPUSHBUTTON   "Ok",IDC_PREF_OK,57,173,50,14

+    PUSHBUTTON      "Cancel",IDC_PREF_CANCEL,115,173,50,14

+    PUSHBUTTON      "Apply",IDC_PREF_APPLY,175,173,50,14

+    CONTROL         "Tab1",IDC_TAB_CONTROL,"SysTabControl32",0x0,7,7,218,159

+END

+

+IDD_ABOUT DIALOGEX 8, 20, 216, 143

+STYLE DS_SETFONT | WS_CHILD

+FONT 8, "Tahoma", 0, 0, 0x0

+BEGIN

+    CONTROL         119,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN | 

+                    WS_BORDER,3,6,88,81

+    CTEXT           "X-Tray\r\nBy: Michael Hotaling\r\n www.SinisterDevelopments.com",

+                    IDC_STATIC,95,33,118,30

+    LTEXT           "Folken\r\nBasket\r\nDonatzsky\r\nDaemon404",IDC_STATIC,

+                    15,103,64,33

+    GROUPBOX        "Special Thanks To:",IDC_STATIC,3,91,89,50

+    GROUPBOX        "Version Information:",IDC_STATIC,101,92,109,49

+    LTEXT           "1.2.4",IDC_STATIC,170,105,33,8,0,WS_EX_RIGHT

+    LTEXT           "Compiled In: ",IDC_STATIC,110,117,54,8

+    LTEXT           "2012",IDC_STATIC,170,117,33,8,0,WS_EX_RIGHT

+    LTEXT           "Version Number:",IDC_STATIC,110,105,54,8

+END

+

+IDD_ALERTS DIALOGEX 8, 20, 216, 143

+STYLE DS_SETFONT | WS_CHILD

+FONT 8, "Tahoma", 0, 0, 0x0

+BEGIN

+    GROUPBOX        "Alerts",IDC_STATIC,5,5,205,117

+    CONTROL         "Only show alerts while minimized",14,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,27,46,117,10

+    CONTROL         "Use tray alerts to notify me about events",13,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,32,152,10

+    CONTROL         "Use window instead of balloons",15,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,27,60,141,11

+    EDITTEXT        IDC_ALERT_TIME,137,101,61,12,ES_AUTOHSCROLL | ES_NUMBER,

+                    WS_EX_RIGHT

+    LTEXT           "Show alert for x seconds:",IDC_ALERT_TIME_TEXT,40,103,

+                    83,9

+    CONTROL         "Alert Hotkey",IDC_ALERT_HOTKEY,"msctls_hotkey32",

+                    WS_BORDER | WS_TABSTOP,137,74,61,13

+    LTEXT           "Close all alerts hotkey:",IDC_ALERT_HOTKEY_TEXT,39,75,

+                    76,10

+    CONTROL         "Leave alerts open indefinately",16,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,27,88,115,11

+    CONTROL         "Blink Icon to alert me about events",18,"Button",

+                    BS_AUTOCHECKBOX | WS_TABSTOP,16,18,127,10

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// DESIGNINFO

+//

+

+#ifdef APSTUDIO_INVOKED

+GUIDELINES DESIGNINFO 

+BEGIN

+    IDD_EVENTS, DIALOG

+    BEGIN

+        BOTTOMMARGIN, 56

+    END

+

+    IDD_SETTINGS, DIALOG

+    BEGIN

+        BOTTOMMARGIN, 66

+    END

+

+    IDD_ALERT, DIALOG

+    BEGIN

+        RIGHTMARGIN, 150

+        BOTTOMMARGIN, 26

+    END

+

+    IDD_PREF, DIALOG

+    BEGIN

+        LEFTMARGIN, 7

+        RIGHTMARGIN, 232

+        TOPMARGIN, 7

+        BOTTOMMARGIN, 176

+    END

+

+    IDD_ABOUT, DIALOG

+    BEGIN

+        LEFTMARGIN, 7

+        RIGHTMARGIN, 209

+        TOPMARGIN, 7

+        BOTTOMMARGIN, 136

+    END

+

+    IDD_ALERTS, DIALOG

+    BEGIN

+        LEFTMARGIN, 7

+        RIGHTMARGIN, 208

+        TOPMARGIN, 7

+        BOTTOMMARGIN, 136

+    END

+END

+#endif    // APSTUDIO_INVOKED

+

+

+#ifdef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// TEXTINCLUDE

+//

+

+1 TEXTINCLUDE 

+BEGIN

+    "resource.h\0"

+END

+

+2 TEXTINCLUDE 

+BEGIN

+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"

+    "#include ""windows.h""\r\n"

+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"

+    "\0"

+END

+

+3 TEXTINCLUDE 

+BEGIN

+    "xtray.h\0"

+END

+

+4 TEXTINCLUDE 

+BEGIN

+    "\r\n"

+    "\0"

+END

+

+#endif    // APSTUDIO_INVOKED

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Version

+//

+

+VS_VERSION_INFO VERSIONINFO

+ FILEVERSION 1,2,4,0

+ PRODUCTVERSION 1,2,4,0

+ FILEFLAGSMASK 0x3fL

+#ifdef _DEBUG

+ FILEFLAGS 0x1L

+#else

+ FILEFLAGS 0x0L

+#endif

+ FILEOS 0x40004L

+ FILETYPE 0x2L

+ FILESUBTYPE 0x0L

+BEGIN

+    BLOCK "StringFileInfo"

+    BEGIN

+        BLOCK "040904b0"

+        BEGIN

+            VALUE "CompanyName", "SinisterDevelopments"

+            VALUE "FileDescription", "X-Tray"

+            VALUE "FileVersion", "1, 2, 4, 0"

+            VALUE "InternalName", "X-Tray"

+            VALUE "LegalCopyright", "Copyright © 2005"

+            VALUE "OriginalFilename", "xtray.dll"

+            VALUE "ProductName", "X-Tray - XChat Win32 System Tray Plugin"

+            VALUE "ProductVersion", "1, 2, 4, 0"

+        END

+    END

+    BLOCK "VarFileInfo"

+    BEGIN

+        VALUE "Translation", 0x409, 1200

+    END

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Menu

+//

+

+IDR_TRAY_MENU MENU 

+BEGIN

+    POPUP "TRAY"

+    BEGIN

+        MENUITEM "Restore",                     ACT_RESTORE

+        MENUITEM SEPARATOR

+        MENUITEM "Away",                        65535

+        MENUITEM "Settings",                    ACT_SETTINGS

+        MENUITEM SEPARATOR

+        MENUITEM "Exit",                        ACT_EXIT

+    END

+END

+

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Icon

+//

+

+// Icon with lowest ID value placed first to ensure application icon

+// remains consistent on all systems.

+ICO_XCHAT               ICON                    "icons\\xchat.ico"

+ICO_BANNED              ICON                    "icons\\banned.ico"

+ICO_CHANMSG             ICON                    "icons\\chan_msg.ico"

+ICO_HIGHLIGHT           ICON                    "icons\\highlight.ico"

+ICO_KICKED              ICON                    "icons\\kicked.ico"

+ICO_PMSG                ICON                    "icons\\priv_msg-1-2-2.ico"

+ICO_SNOTICE             ICON                    "icons\\server_notice.ico"

+ICO_DISCONNECTED        ICON                    "icons\\disconnected.ico"

+

+/////////////////////////////////////////////////////////////////////////////

+//

+// Bitmap

+//

+

+IDB_SD_LOGO             BITMAP                  "bitmaps\\sd.bmp"

+#endif    // English (U.S.) resources

+/////////////////////////////////////////////////////////////////////////////

+

+

+

+#ifndef APSTUDIO_INVOKED

+/////////////////////////////////////////////////////////////////////////////

+//

+// Generated from the TEXTINCLUDE 3 resource.

+//

+xtray.h

+/////////////////////////////////////////////////////////////////////////////

+#endif    // not APSTUDIO_INVOKED

+

diff --git a/plugins/xtray/sdAlerts.cpp b/plugins/xtray/sdAlerts.cpp
new file mode 100644
index 00000000..5e042806
--- /dev/null
+++ b/plugins/xtray/sdAlerts.cpp
@@ -0,0 +1,109 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <windows.h>

+#include <winuser.h>

+#include <stdio.h>

+#include "utility.h"

+#include "resource.h"

+#include "sdAlerts.h"

+

+int g_iAlerts = 0;

+

+void sdSystemAlert(HINSTANCE hModule, UINT uiDialog, char *szMsg, char *szName, unsigned int iTime)

+{

+	TCHAR wszMsg[256];

+	TCHAR wszName[64];

+

+	HWND hDialog;

+	RECT rcWorkArea, rcDlg;

+	int ixPos, iyPos;

+	int iNumPerCol;

+	

+	hDialog = CreateDialog(hModule, MAKEINTRESOURCE(uiDialog), NULL, (DLGPROC)sdAlertProc);

+

+	SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);

+	GetWindowRect(hDialog, &rcDlg);

+

+	iNumPerCol = ((rcWorkArea.bottom - rcWorkArea.top) / (rcDlg.bottom - rcDlg.top));

+	ixPos = rcWorkArea.right - (rcDlg.right - rcDlg.left) + 1;

+	iyPos = rcWorkArea.bottom - (rcDlg.bottom - rcDlg.top);

+

+	if((g_iAlerts >= iNumPerCol) && (iNumPerCol > 0))

+	{

+		ixPos -= ((g_iAlerts / iNumPerCol) * (rcDlg.right - rcDlg.left));

+		iyPos -= ((g_iAlerts - (iNumPerCol * (g_iAlerts / iNumPerCol))) * (rcDlg.bottom - rcDlg.top));

+	}

+	else

+	{

+		iyPos -= (g_iAlerts * (rcDlg.bottom - rcDlg.top));

+	}

+	SetWindowPos(hDialog, HWND_TOPMOST, ixPos, iyPos, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);

+	

+	ConvertString(szName, wszName, 64);

+	ConvertString(szMsg, wszMsg, 256);

+

+	SetWindowText(hDialog, wszName);

+	SetDlgItemText(hDialog, IDC_ALERT_MSG, wszMsg);

+	ShowWindow(hDialog, SW_SHOWNA);

+

+	if(iTime > 0)

+	{

+		SetTimer(hDialog, 1, iTime, NULL);

+	}

+

+	g_iAlerts++;

+}

+

+void sdCloseAlerts()

+{

+	PostMessage(HWND_BROADCAST, RegisterWindowMessage(TEXT("xTray:CloseAllAlertWindows")), 0, 0);

+}

+

+LRESULT CALLBACK sdAlertProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)

+{

+	switch(msg)

+	{

+	case WM_CLOSE:

+		if(g_iAlerts > 0){ g_iAlerts--; }

+		DestroyWindow(hwnd);

+		return TRUE;

+		break;

+	case WM_TIMER:

+		if(g_iAlerts > 0){ g_iAlerts--; }

+		AnimateWindow(hwnd, 600, AW_SLIDE | AW_HIDE | AW_VER_POSITIVE);

+		DestroyWindow(hwnd);

+		return TRUE;

+		break;

+	default:

+		if(msg == RegisterWindowMessage(TEXT("xTray:CloseAllAlertWindows")))

+		{

+			if(g_iAlerts > 0){ g_iAlerts--; }

+			DestroyWindow(hwnd);

+			return TRUE;

+		}

+		break;

+	}

+

+	return FALSE;

+}

+

+int sdAlertNum()

+{

+	return g_iAlerts;

+}
\ No newline at end of file
diff --git a/plugins/xtray/sdAlerts.h b/plugins/xtray/sdAlerts.h
new file mode 100644
index 00000000..cd45a05b
--- /dev/null
+++ b/plugins/xtray/sdAlerts.h
@@ -0,0 +1,26 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _H_SDALERTS_H

+#define _H_SDALERTS_H

+

+void				sdSystemAlert	(HINSTANCE, UINT, char *, char *, UINT);

+LRESULT CALLBACK	sdAlertProc		(HWND, UINT, WPARAM, LPARAM);

+int					sdAlertNum		();

+void				sdCloseAlerts	();

+#endif
\ No newline at end of file
diff --git a/plugins/xtray/sdTray.cpp b/plugins/xtray/sdTray.cpp
new file mode 100644
index 00000000..3a91a61b
--- /dev/null
+++ b/plugins/xtray/sdTray.cpp
@@ -0,0 +1,207 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#define _WIN32_IE 0x601

+#include <windows.h>

+#include <stdio.h>

+#include <tchar.h>

+#include "sdTray.h"

+#include "utility.h"

+

+HANDLE hThread;

+iBlink *tData	= NULL;

+

+int AddIcon(HWND hwnd, UINT id, HICON hicon, char *szTip, unsigned short flags, unsigned int cbMsg)

+{

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize			= NOTIFYICONDATA_V2_SIZE;

+	nidata.hIcon			= hicon;

+	nidata.hWnd				= hwnd;

+	nidata.uCallbackMessage = cbMsg;

+	nidata.uFlags			= flags;

+	nidata.uID				= id;

+

+	if(szTip != NULL)

+	{

+		TCHAR *szTemp = new TCHAR[64];

+

+		ConvertString(szTip, szTemp, 64);

+		_tcsncpy(nidata.szTip, szTemp, 64);

+

+		delete[] szTemp;

+	}

+

+	return Shell_NotifyIcon(NIM_ADD, &nidata);

+}

+

+int RemoveIcon(HWND hwnd, UINT id)

+{

+	if(hThread != NULL)

+	{

+		TerminateThread(hThread, 0);

+		hThread = NULL;

+

+		delete tData;

+	}

+

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize = NOTIFYICONDATA_V2_SIZE;

+	nidata.hWnd   = hwnd;

+	nidata.uID    = id;

+

+	return Shell_NotifyIcon(NIM_DELETE, &nidata);

+}

+

+int SetIcon(HWND hwnd, UINT id, HICON hicon)

+{

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize = NOTIFYICONDATA_V2_SIZE;

+	nidata.hWnd   = hwnd;

+	nidata.uID    = id;

+	nidata.hIcon  = hicon;

+	nidata.uFlags = NIF_ICON;

+

+	return Shell_NotifyIcon(NIM_MODIFY, &nidata);

+}

+

+int SetTooltip(HWND hwnd, UINT id, char *szTip)

+{

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize = NOTIFYICONDATA_V2_SIZE;

+	nidata.hWnd   = hwnd;

+	nidata.uID    = id;

+	nidata.uFlags = NIF_TIP;

+

+	if(szTip != NULL)

+	{

+		TCHAR *szTemp = new TCHAR[64];

+		ConvertString(szTip, szTemp, 64);

+		_tcsncpy(nidata.szTip, szTemp, 64);

+		delete[] szTemp;

+	}

+

+	return Shell_NotifyIcon(NIM_MODIFY, &nidata);

+}

+

+int ShowBalloon(HWND hwnd, UINT id, char *szInfo, char *szTitle, UINT time, UINT infoFlags)

+{

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize	= NOTIFYICONDATA_V2_SIZE;

+	nidata.hWnd		= hwnd;

+	nidata.uID		= id;

+	nidata.uFlags	= NIF_INFO;

+	nidata.dwInfoFlags = infoFlags;

+

+	if(time > 0)

+		nidata.uTimeout = time;

+	else

+		nidata.uTimeout = 500000;

+

+	if(szInfo != NULL)

+	{

+		TCHAR *szTemp = new TCHAR[255];

+

+		ConvertString(szInfo, szTemp, 251);

+		szTemp[250] = 0;

+		

+		if(strlen(szInfo) > 255)

+		{

+			_sntprintf(szTemp, 255, _T("%s..."), szTemp);

+		}

+		_tcsncpy(nidata.szInfo, szTemp, 255);

+

+		delete[] szTemp;

+	}

+	if(szTitle != NULL)

+	{

+		TCHAR *wszTitle = new TCHAR[64];

+		ConvertString(szTitle, wszTitle, 64);

+		_tcsncpy(nidata.szInfoTitle, wszTitle, 64);

+		delete[] wszTitle;

+	}

+

+	return Shell_NotifyIcon(NIM_MODIFY, &nidata);

+}

+

+

+DWORD WINAPI BlinkThread(LPVOID lpParam)

+{

+	NOTIFYICONDATA nidata;

+

+	nidata.cbSize = NOTIFYICONDATA_V2_SIZE;

+	nidata.hWnd   = tData->hwnd;

+	nidata.uID    = tData->id;

+	nidata.uFlags = NIF_ICON;

+

+	for(UINT i = 0; i < tData->num; i++)

+	{

+		nidata.hIcon = tData->hBlink;

+		Shell_NotifyIcon(NIM_MODIFY, &nidata);

+

+		Sleep(tData->time);

+

+		nidata.hIcon = tData->hBase;

+		Shell_NotifyIcon(NIM_MODIFY, &nidata);

+

+		Sleep(tData->time);

+	}

+

+	delete tData;

+	hThread = NULL;

+

+	return 0;

+}

+

+int BlinkIcon(HWND hwnd, UINT id, HICON hBase, HICON hBlink, UINT time, UINT num)

+{

+	if(hThread != NULL)

+	{

+		StopBlink(hwnd, id, hBase);

+	}

+

+	DWORD dwThreadID;

+	tData = new iBlink;

+

+	tData->hwnd		= hwnd;

+	tData->id		= id;

+	tData->hBase	= hBase;

+	tData->hBlink	= hBlink;

+	tData->time		= time;

+	tData->num		= num;

+

+	hThread = CreateThread(NULL, 0, BlinkThread, tData, 0, &dwThreadID);

+

+	return 0;

+}

+

+void StopBlink(HWND hwnd, UINT id, HICON hBase)

+{

+	if(hThread != NULL)

+	{

+		TerminateThread(hThread, 0);

+		hThread = NULL;

+

+		delete tData;

+	}

+

+	SetIcon(hwnd, id, hBase);

+}
\ No newline at end of file
diff --git a/plugins/xtray/sdTray.h b/plugins/xtray/sdTray.h
new file mode 100644
index 00000000..68469fe0
--- /dev/null
+++ b/plugins/xtray/sdTray.h
@@ -0,0 +1,39 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _H_SDTRAY_H

+#define _H_SDTRAY_H

+

+int				AddIcon		(HWND, UINT, HICON, char *, unsigned short, UINT);

+int				ShowBalloon	(HWND, UINT, char *, char *, UINT, UINT);

+int				BlinkIcon	(HWND, UINT, HICON, HICON, UINT, UINT);

+int				SetTooltip	(HWND, UINT, char *);

+int				SetIcon		(HWND, UINT, HICON);

+void			StopBlink	(HWND, UINT, HICON);

+int				RemoveIcon	(HWND, UINT);

+

+typedef struct IBLINK

+{

+	HICON hBase;

+	HICON hBlink;

+	HWND hwnd;

+	UINT id;

+	UINT time;

+	UINT num;

+}iBlink;

+#endif
\ No newline at end of file
diff --git a/plugins/xtray/utility.cpp b/plugins/xtray/utility.cpp
new file mode 100644
index 00000000..66489bc0
--- /dev/null
+++ b/plugins/xtray/utility.cpp
@@ -0,0 +1,607 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <windows.h>

+#include <stdio.h>

+#include <commctrl.h>

+#include <tchar.h>

+

+#include "xchat-plugin.h"

+#include "utility.h"

+#include "xtray.h"

+#include "callbacks.h"

+#include "resource.h"

+

+TCHAR BACKUP_INI_FILE[] = _T(".\\plugins\\config\\xtray.conf");

+struct HOTKEY g_hHotKey;

+

+/* we need to convert ALT and SHIFT modifiers

+// from <winuser.h>

+#define MOD_ALT         0x0001

+#define MOD_CONTROL     0x0002

+#define MOD_SHIFT       0x0004

+// from <commctrl.h>

+#define HOTKEYF_SHIFT           0x01

+#define HOTKEYF_CONTROL         0x02

+#define HOTKEYF_ALT             0x04

+*/

+

+WORD HotkeyfToMod(WORD modifiers)

+{

+	WORD newmods = 0;

+

+	if (modifiers & HOTKEYF_SHIFT)

+		newmods |= MOD_SHIFT;

+

+	if (modifiers & HOTKEYF_CONTROL)

+		newmods |= MOD_CONTROL;

+

+	if (modifiers & HOTKEYF_ALT)

+		newmods |= MOD_ALT;

+

+	return newmods;

+}

+

+WORD ModToHotkeyf(WORD modifiers)

+{

+	WORD newmods = 0;

+

+	if (modifiers & MOD_SHIFT)

+		newmods |= HOTKEYF_SHIFT;

+

+	if (modifiers & MOD_CONTROL)

+		newmods |= HOTKEYF_CONTROL;

+

+	if (modifiers & MOD_ALT)

+		newmods |= HOTKEYF_ALT;

+

+	return newmods;

+}

+

+void SavePrefs(int iDlg)

+{

+	/**************************************************************************************************/

+	/********** allocate space for our string, and then set it to the currently logged on user ********/

+	/**************************************************************************************************/

+	DWORD dBuff = 257;

+	TCHAR szUser[257];

+

+	GetUserName(szUser, &dBuff);

+

+	/**************************************************************************************************/

+	/*********************** Test if the file exists, If it doesn't, Create It ************************/

+	/**************************************************************************************************/

+	TCHAR XTRAY_INI_FILE[1024];

+	

+#ifdef UNICODE

+	char temp[1024];

+    TCHAR TEMP_INI_FILE[1024];

+	

+	_snprintf(temp, 1024, "%s\\xtray.conf", xchat_get_info(ph, "xchatdir"));

+	ConvertString(temp, TEMP_INI_FILE, 1024);

+

+	// ok this one is really ugly

+	// it checks to see if the file exists in two locations

+	// X-Chat default config dir, if that fails it trys xchat\plugins\config

+	// if neither one exists it tries to create it in

+	// X-Chat default config dir, if that fails it trys xchat\plugins\config

+	// In either case it writes \xFF\xFE to the file ( on creation )

+	// so that we can save unicode away messages WritePrivateProfile doesn't 

+	// do this for us, though I think it really should

+

+	if(FileExists(TEMP_INI_FILE))

+	{

+		_tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE);

+	}

+	else

+	{

+		if(FileExists(BACKUP_INI_FILE))

+		{

+			_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+		}

+		else

+		{

+			HANDLE xTemp;

+			DWORD dwBytesTemp;

+

+			if(xTemp = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL))

+			{

+				if(GetLastError() != ERROR_ALREADY_EXISTS)

+				{

+					WriteFile(xTemp, _T("\xFF\xFE"), 4, &dwBytesTemp, NULL);

+				}

+				CloseHandle(xTemp);

+			}

+

+			if(FileExists(TEMP_INI_FILE))

+			{

+				_tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE);

+			}

+			else

+			{

+				HANDLE xBackup;

+				DWORD dwBytesBackup;

+

+				if(xBackup = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL))

+				{

+					if(GetLastError() != ERROR_ALREADY_EXISTS)

+					{

+						WriteFile(xBackup, _T("\xFF\xFE"), 4, &dwBytesBackup, NULL);

+					}

+

+					CloseHandle(xBackup);

+				}

+

+				if(FileExists(BACKUP_INI_FILE))

+				{

+					_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+				}

+			}

+		}

+	}

+

+#else

+	_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+#endif

+

+	WritePrivateProfileInt(szUser, _T("SETTINGS"),		g_dwPrefs,		XTRAY_INI_FILE);

+	WritePrivateProfileInt(szUser, _T("AOT"),			g_iTime,		XTRAY_INI_FILE);

+	WritePrivateProfileInt(szUser, _T("KEY"),			g_hHotKey.key,	XTRAY_INI_FILE);

+	WritePrivateProfileInt(szUser, _T("MOD"),			g_hHotKey.mod,	XTRAY_INI_FILE);

+	WritePrivateProfileString(szUser, _T("AWAY"),		g_szAway,		XTRAY_INI_FILE);

+}

+

+void LoadPrefs()

+{

+	/**************************************************************************************************/

+	/*********************** Our Settings Section *****************************************************/

+	/**************************************************************************************************/

+	DWORD dBuff = 257;

+	TCHAR szUser[257];

+

+	GetUserName(szUser, &dBuff);

+

+	/**************************************************************************************************/

+	/*********************** Test if the file exists, If it doesn't, Create It ************************/

+	/**************************************************************************************************/

+	TCHAR XTRAY_INI_FILE[1024];

+

+#ifdef UNICODE

+	char temp[1024];

+	TCHAR TEMP_INI_FILE[1024];

+

+	_snprintf(temp, 1024, "%s\\xtray.conf", xchat_get_info(ph, "xchatdir"));

+	ConvertString(temp, TEMP_INI_FILE, 1024);

+

+	if(FileExists(TEMP_INI_FILE))

+	{

+		_tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE);

+	}

+	else

+	{

+		if(FileExists(BACKUP_INI_FILE))

+		{

+			_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+		}

+		else

+		{

+			HANDLE xTemp;

+			DWORD dwBytesTemp;

+

+			if(xTemp = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL))

+			{

+				if(GetLastError() != ERROR_ALREADY_EXISTS)

+				{

+					WriteFile(xTemp, _T("\xFF\xFE"), 4, &dwBytesTemp, NULL);

+				}

+

+				CloseHandle(xTemp);

+			}

+

+			if(FileExists(TEMP_INI_FILE))

+			{

+				_tcscpy(XTRAY_INI_FILE, TEMP_INI_FILE);

+			}

+			else

+			{

+				HANDLE xBackup;

+				DWORD dwBytesBackup;

+

+				if(xBackup = CreateFile(TEMP_INI_FILE, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL))

+				{

+					if(GetLastError() != ERROR_ALREADY_EXISTS)

+					{

+						WriteFile(xBackup, _T("\xFF\xFE"), 4, &dwBytesBackup, NULL);

+					}

+

+					CloseHandle(xBackup);

+				}

+

+				if(FileExists(BACKUP_INI_FILE))

+				{

+					_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+				}

+			}

+		}

+	}

+

+#else

+	_tcscpy(XTRAY_INI_FILE, BACKUP_INI_FILE);

+#endif

+

+	/**************************************************************************************************/

+	/*************************** Get the value for each of our preferances ****************************/

+	/**************************************************************************************************/

+	g_dwPrefs = GetPrivateProfileInt(szUser, _T("SETTINGS"),	0,  XTRAY_INI_FILE);

+

+	// backwards compatability

+	// also allows us to set defaults if its a new installation

+	// disable topic change, channel message and server notice by default

+	if(g_dwPrefs == 0)

+	{

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("HILIGHT"),		1,  XTRAY_INI_FILE)<<1);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("INVITE"),		1,  XTRAY_INI_FILE)<<2);

+		/* g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("TOPIC"),		1,  XTRAY_INI_FILE)<<3); */

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("BANNED"),		1,  XTRAY_INI_FILE)<<4);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("KICKED"),		1,  XTRAY_INI_FILE)<<5);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("CTCP"),		1,  XTRAY_INI_FILE)<<6);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("PMSG"),		1,  XTRAY_INI_FILE)<<7);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("KILLED"),		1,  XTRAY_INI_FILE)<<8);

+		/* g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("NOTICE"),		1,  XTRAY_INI_FILE)<<9); */

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("DISCONNECT"),	1,  XTRAY_INI_FILE)<<10);

+

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("AOM"),			0,  XTRAY_INI_FILE)<<11);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("TOT"),			1,  XTRAY_INI_FILE)<<12);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("AMAE"),		1,  XTRAY_INI_FILE)<<13);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("OSBWM"),		0,  XTRAY_INI_FILE)<<14);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("UWIOB"),		0,  XTRAY_INI_FILE)<<15);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("KAOI"),		0,  XTRAY_INI_FILE)<<16);

+		g_dwPrefs	|= (GetPrivateProfileInt(szUser, _T("MIOC"),		0,  XTRAY_INI_FILE)<<17);

+	}

+	

+	g_hHotKey.key	= GetPrivateProfileInt(szUser, _T("KEY"),	84, XTRAY_INI_FILE);

+	g_hHotKey.mod	= GetPrivateProfileInt(szUser, _T("MOD"),	(MOD_CONTROL | MOD_SHIFT),  XTRAY_INI_FILE);

+	g_iTime			= GetPrivateProfileInt(szUser, _T("AOT"),	5,  XTRAY_INI_FILE);

+

+	GetPrivateProfileString(szUser, _T("AWAY"), _T(""),	g_szAway, 1024, XTRAY_INI_FILE);

+	

+	/**************************************************************************************************/

+	/******************************** Register our hotkey with windows ********************************/

+	/**************************************************************************************************/

+	if(g_dwPrefs & (1<<PREF_UWIOB))

+	{

+		RegisterHotKey(g_hHotkeyWnd, 1, g_hHotKey.mod, g_hHotKey.key);

+	}

+}

+

+void CheckPrefs(HWND hwnd, int iDlg)

+{

+	/**************************************************************************************************/

+	/**************** save the preferances based on the checkmarks/options ****************************/

+	/**************************************************************************************************/

+	switch(iDlg)

+	{

+	case IDD_EVENTS:

+		{

+			SetOption(hwnd, CHAN_HILIGHT,		CHAN_HILIGHT);

+			SetOption(hwnd, CHAN_INVITE,		CHAN_INVITE);

+			SetOption(hwnd, CHAN_TOPIC_CHANGE,	CHAN_TOPIC_CHANGE);

+			SetOption(hwnd, CHAN_BANNED,		CHAN_BANNED);

+			SetOption(hwnd, CHAN_KICKED,		CHAN_KICKED);

+			SetOption(hwnd, CTCP_GENERIC,		CTCP_GENERIC);

+			SetOption(hwnd, PMSG_RECEIVE,		PMSG_RECEIVE);

+			SetOption(hwnd, SERV_KILLED,		SERV_KILLED);

+			SetOption(hwnd, SERV_NOTICE,		SERV_NOTICE);

+			SetOption(hwnd, SERV_DISCONNECT,	SERV_DISCONNECT);

+			SetOption(hwnd, CHAN_MESSAGE,		CHAN_MESSAGE);

+		}

+		break;

+	case IDD_ALERTS:

+		{

+			SetOption(hwnd, PREF_AMAE,	PREF_AMAE);

+			SetOption(hwnd, PREF_OSBWM,	PREF_OSBWM);

+			SetOption(hwnd, PREF_UWIOB,	PREF_UWIOB);

+			SetOption(hwnd, PREF_KAOI,	PREF_KAOI);

+			SetOption(hwnd, PREF_BLINK,	PREF_BLINK);

+

+			/**************************************************************************/

+			/**************************************************************************/

+			/**************************************************************************/

+			TCHAR tTime[512];

+

+			GetWindowText(GetDlgItem(hwnd, IDC_ALERT_TIME), tTime, 511);

+			

+			g_iTime = _tstoi(tTime);

+			

+			/**************************************************************************/

+			/**************** Get our Hotkey and save it                     **********/

+			/**************** then remove the old hotkey and add the new one **********/

+			/**************************************************************************/

+			DWORD hHotkey;

+			hHotkey = SendDlgItemMessage(hwnd, IDC_ALERT_HOTKEY, HKM_GETHOTKEY, 0, 0);

+			

+			g_hHotKey.key = LOBYTE(hHotkey);

+			g_hHotKey.mod = HotkeyfToMod(HIBYTE(hHotkey));

+			

+			if(IsDlgButtonChecked(hwnd, PREF_UWIOB) == BST_CHECKED)

+			{

+				UnregisterHotKey(g_hHotkeyWnd, 1);

+				RegisterHotKey(g_hHotkeyWnd, 1, g_hHotKey.mod, g_hHotKey.key);

+			}

+			else

+			{

+				UnregisterHotKey(g_hHotkeyWnd, 1);

+			}

+

+			/*************************************************************************/

+			/*********** Get and save the away msg and alert time ********************/

+			/*************************************************************************/

+		}

+		break;

+	case IDD_SETTINGS:

+		{

+			SetOption(hwnd, PREF_AOM, PREF_AOM);

+			SetOption(hwnd, PREF_TOT, PREF_TOT);

+			SetOption(hwnd, PREF_MIOC, PREF_MIOC);

+			SetOption(hwnd, PREF_DNSIT, PREF_DNSIT);

+

+			GetDlgItemText(hwnd, IDC_AWAY_MSG, g_szAway, 511);

+

+			if(g_dwPrefs & (1<<PREF_DNSIT))

+			{

+				DWORD dwStyle;

+				dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE);

+				dwStyle |= (1<<WS_CHILD);

+				SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle);

+				SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, (LONG_PTR)g_hHotkeyWnd);

+			}

+			else

+			{

+				DWORD dwStyle;

+				dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE);

+				dwStyle &= ~(1<<WS_CHILD);

+				SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle);

+				SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, NULL);

+			}

+		}

+		break;

+	} 

+}

+

+void SetDialog(HWND hwnd, int iDlg)

+{

+	switch(iDlg)

+	{

+	case IDD_EVENTS:

+		{

+			SetCheck(hwnd, CHAN_HILIGHT,		CHAN_HILIGHT);

+			SetCheck(hwnd, CHAN_INVITE,			CHAN_INVITE);

+			SetCheck(hwnd, CHAN_TOPIC_CHANGE,	CHAN_TOPIC_CHANGE);

+			SetCheck(hwnd, CHAN_BANNED,			CHAN_BANNED);

+			SetCheck(hwnd, CHAN_KICKED,			CHAN_KICKED);

+			SetCheck(hwnd, CTCP_GENERIC,		CTCP_GENERIC);

+			SetCheck(hwnd, PMSG_RECEIVE,		PMSG_RECEIVE);

+			SetCheck(hwnd, SERV_KILLED,			SERV_KILLED);

+			SetCheck(hwnd, SERV_NOTICE,			SERV_NOTICE);

+			SetCheck(hwnd, SERV_DISCONNECT,		SERV_DISCONNECT);

+			SetCheck(hwnd, CHAN_MESSAGE,		CHAN_MESSAGE);

+		}

+		break;

+	case IDD_SETTINGS:

+		{

+			SetCheck(hwnd, PREF_TOT,	PREF_TOT);

+			SetCheck(hwnd, PREF_MIOC,	PREF_MIOC);

+			SetCheck(hwnd, PREF_AOM,	PREF_AOM);

+			SetCheck(hwnd, PREF_DNSIT,	PREF_DNSIT);

+

+			SetDlgItemText(hwnd, IDC_AWAY_MSG, g_szAway);

+		}

+		break;

+	case IDD_ALERTS:

+		{

+			

+			SetCheck(hwnd, PREF_BLINK,	PREF_BLINK);

+			SetCheck(hwnd, PREF_OSBWM,	PREF_OSBWM);

+			SetCheck(hwnd, PREF_UWIOB,	PREF_UWIOB);

+			SetCheck(hwnd, PREF_KAOI,	PREF_KAOI);

+

+			/**********************************************************/

+			/**********************************************************/

+			/**********************************************************/

+			if(SetCheck(hwnd, PREF_AMAE, PREF_AMAE) == false)

+			{

+				SetToggle(hwnd, PREF_OSBWM,				PREF_AMAE, TRUE);

+				SetToggle(hwnd, PREF_UWIOB,				PREF_AMAE, TRUE);

+				SetToggle(hwnd, PREF_KAOI,				PREF_AMAE, TRUE);

+				SetToggle(hwnd, IDC_ALERT_TIME,			PREF_AMAE, TRUE);

+				SetToggle(hwnd, IDC_ALERT_TIME_TEXT,	PREF_AMAE, TRUE);

+				SetToggle(hwnd, IDC_ALERT_HOTKEY,		PREF_AMAE, TRUE);

+				SetToggle(hwnd, IDC_ALERT_HOTKEY_TEXT,	PREF_AMAE, TRUE);

+			}

+			else

+			{

+

+				SetToggle(hwnd, IDC_ALERT_HOTKEY,		PREF_UWIOB, TRUE);

+				SetToggle(hwnd, IDC_ALERT_HOTKEY_TEXT,	PREF_UWIOB, TRUE);

+				SetToggle(hwnd, IDC_ALERT_TIME,			PREF_KAOI, FALSE);

+				SetToggle(hwnd, IDC_ALERT_TIME_TEXT,	PREF_KAOI, FALSE);

+			}

+

+			/**********************************************************/

+			/**********************************************************/

+			/**********************************************************/

+			TCHAR tTime[255];

+			SendDlgItemMessage(hwnd, IDC_ALERT_TIME,	WM_SETTEXT, 0, (LPARAM)_itot(g_iTime, tTime, 10));

+			SendDlgItemMessage(hwnd, IDC_ALERT_HOTKEY,	HKM_SETHOTKEY, MAKEWORD(g_hHotKey.key, ModToHotkeyf(g_hHotKey.mod)), 0);

+		}

+		break;

+	}

+}

+

+int SetCheck(HWND hDialog, unsigned int uiCheckBox, unsigned int uiPref)

+{

+	if((g_dwPrefs & (1<<uiPref)))

+	{

+		CheckDlgButton(hDialog, uiCheckBox, BST_CHECKED);

+		return 1;

+	}

+	else

+	{

+		CheckDlgButton(hDialog, uiCheckBox, BST_UNCHECKED);

+		return 0;

+	}

+

+	return 0;

+}

+

+int SetToggle(HWND hDialog, unsigned int uiCheckBox, unsigned int uiTestbox, bool offeqoff)

+{

+	/**************************************************************************************************/

+	/*********************** if(true) then if option is off turn toggle off ***************************/

+	/*********************** if(false) then if option is off turn toggle on ***************************/

+	/**************************************************************************************************/

+	if(offeqoff)

+	{

+		if(IsDlgButtonChecked(hDialog, uiTestbox) == BST_CHECKED)

+		{

+			EnableWindow(GetDlgItem(hDialog, uiCheckBox), TRUE);

+			return 1;

+		}

+		else

+		{

+			EnableWindow(GetDlgItem(hDialog, uiCheckBox), FALSE);

+			return 0;

+		}

+	}

+	else

+	{

+		if(IsDlgButtonChecked(hDialog, uiTestbox) == BST_CHECKED)

+		{

+			EnableWindow(GetDlgItem(hDialog, uiCheckBox), FALSE);

+			return 1;

+		}

+		else

+		{

+			EnableWindow(GetDlgItem(hDialog, uiCheckBox), TRUE);

+			return 0;

+		}

+	}

+

+	return 0;

+}

+

+int SetOption(HWND hDialog, unsigned int uiCheckBox, unsigned int uiPref)

+{

+	if(IsDlgButtonChecked(hDialog, uiCheckBox) == BST_CHECKED)

+	{

+		g_dwPrefs |= (1<<uiPref);

+	}

+	else

+	{

+		g_dwPrefs &= ~(1<<uiPref);

+	}

+

+	return (g_dwPrefs & (1<<uiPref));

+}

+

+int WritePrivateProfileIntA(char *szSection, char *szItem, int iData, char *szPath)

+{

+	char szData[33];

+	itoa(iData, szData, 10);

+	return WritePrivateProfileStringA(szSection, szItem, szData, szPath);

+}

+

+int WritePrivateProfileIntW(wchar_t *wszSection, wchar_t *wszItem, int iData, wchar_t *wszPath)

+{

+	wchar_t wszData[33];

+	_itow(iData, wszData, 10);

+	return WritePrivateProfileStringW(wszSection, wszItem, wszData, wszPath);

+}

+

+// For cleanup ( Closing windows and the such )

+void HoldClose()

+{

+	HANDLE hcThread;

+	DWORD dwThreadID;

+	hcThread = CreateThread(NULL, 0, HoldCloseThread, 0, 0, &dwThreadID);

+}

+

+DWORD WINAPI HoldCloseThread(LPVOID lpParam)

+{

+	Sleep(1000);

+	PostMessage(g_hXchatWnd, WM_CLOSE, 0, 0);

+	return 0;

+}

+

+bool FileExists(TCHAR *file)

+{

+	HANDLE hTemp = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

+	int nRet = GetLastError();

+	CloseHandle(hTemp);

+

+	if(nRet == 0)

+	{

+		return true;

+	}

+	else

+	{

+		return false;

+	}

+

+	return false;

+}

+

+void ConvertString(const char *in, wchar_t *out, int size)

+{

+	MultiByteToWideChar(CP_UTF8, 0, in,  -1, out, size);

+}

+

+void ConvertString(const wchar_t *in, char *out, int size)

+{

+	WideCharToMultiByte(CP_UTF8, 0, in, (size - 1), out, size, NULL, NULL);

+}

+

+void ConvertString(const char *in, char *out, int size)

+{

+	strncpy(out, in, size);

+}

+

+void ErrorDebug(LPTSTR lpszFunction)

+{ 

+    TCHAR szBuf[80]; 

+    LPVOID lpMsgBuf;

+    DWORD dw = GetLastError(); 

+

+    FormatMessage(

+        FORMAT_MESSAGE_ALLOCATE_BUFFER | 

+        FORMAT_MESSAGE_FROM_SYSTEM,

+        NULL,

+        dw,

+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

+        (LPTSTR) &lpMsgBuf,

+        0, NULL );

+

+    _stprintf(szBuf, 

+        _T("%s failed with error %d: %s"), 

+        lpszFunction, dw, lpMsgBuf); 

+ 

+    MessageBox(NULL, szBuf, _T("Error"), MB_OK); 

+

+    LocalFree(lpMsgBuf);

+}

+

diff --git a/plugins/xtray/utility.h b/plugins/xtray/utility.h
new file mode 100644
index 00000000..6bee8aed
--- /dev/null
+++ b/plugins/xtray/utility.h
@@ -0,0 +1,55 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _H_UTILITY_H

+#define _H_UTILITY_H

+

+WORD					HotkeyfToMod	(WORD);

+WORD					ModToHotkeyf	(WORD);

+

+int						SetOption		(HWND, unsigned int, unsigned int);

+int						SetCheck		(HWND, unsigned int, unsigned int);

+int						SetToggle		(HWND, unsigned int, unsigned int, bool);

+void					ErrorDebug		(LPTSTR lpszFunction);

+void					SetDialog		(HWND, int);

+void					CheckPrefs		(HWND, int);

+bool					FileExists		(TCHAR *);

+DWORD WINAPI			HoldCloseThread	(LPVOID);

+void					SavePrefs		(int);

+void					LoadPrefs		();

+void					HoldClose		();

+

+void ConvertString(const char *in,		wchar_t *out,	int size);

+void ConvertString(const wchar_t *in,	char *out,		int size);

+void ConvertString(const char *in,		char *out,		int size);

+

+int WritePrivateProfileIntA(char *, char *, int, char *);

+int WritePrivateProfileIntW(wchar_t *, wchar_t *, int, wchar_t *);

+

+#ifdef UNICODE

+#define WritePrivateProfileInt WritePrivateProfileIntW

+#else

+#define WritePrivateProfileInt WritePrivateProfileIntA

+#endif

+

+struct HOTKEY

+{

+	WORD key;

+	WORD mod;

+};

+#endif
\ No newline at end of file
diff --git a/plugins/xtray/xchat.cpp b/plugins/xtray/xchat.cpp
new file mode 100644
index 00000000..47ce46a9
--- /dev/null
+++ b/plugins/xtray/xchat.cpp
@@ -0,0 +1,320 @@
+/* X-Tray

+ * Copyright (C) 1998, 2005 Peter Zelezny, Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <windows.h>

+#include <vector>

+#include <algorithm>

+#include <stdio.h>

+#include <tchar.h>

+

+#include "xchat-plugin.h"

+#include "xtray.h"

+#include "resource.h"

+#include "xchat.h"

+#include "utility.h"

+

+// from util.c of xchat source code ( slightly modified to fit X-Tray Syntax )

+char *xchat_strip_color (char *text)

+{

+	int nc	= 0;

+	int i	= 0;

+	int col	= 0;

+	int len	= strlen(text);

+	char *new_str = (char *)malloc(len + 2);

+

+	while (len > 0)

+	{

+		if ((col && isdigit(*text) && (nc < 2)) || (col && isdigit(*(text+1)) && (nc < 3) && (*text == ',')))

+		{

+			nc++;

+

+			if(*text == ',')

+			{

+				nc = 0;

+			}

+		}

+		else

+		{

+			col = 0;

+

+			switch (*text)

+			{

+			case '\003':			  /*ATTR_COLOR: */

+				{

+					col = 1;

+					nc = 0;

+				}

+				break;

+			case '\007':			  /*ATTR_BEEP: */

+			case '\017':			  /*ATTR_RESET: */

+			case '\026':			  /*ATTR_REVERSE: */

+			case '\002':			  /*ATTR_BOLD: */

+			case '\037':			  /*ATTR_UNDERLINE: */

+				break;

+			default:

+				{

+					new_str[i] = *text;

+					i++;

+				}

+				break;

+			}

+		}

+

+		text++;

+		len--;

+	}

+

+	new_str[i] = 0;

+

+	return new_str;

+}

+

+void check_special_chars (char *cmd)

+{

+	int occur	= 0;

+	int len		= strlen (cmd);

+	int i = 0, j = 0;

+	char *buf;

+

+	if (!len)

+		return;

+

+	buf = (char *)malloc (len + 1);

+

+	if (buf)

+	{

+		while (cmd[j])

+		{

+			switch (cmd[j])

+			{

+			case '%':

+				{

+					occur++;

+

+					switch (cmd[j + 1])

+					{

+					case 'R':

+						buf[i] = '\026';

+						break;

+					case 'U':

+						buf[i] = '\037';

+						break;

+					case 'B':

+						buf[i] = '\002';

+						break;

+					case 'C':

+						buf[i] = '\003';

+						break;

+					case 'O':

+						buf[i] = '\017';

+						break;

+					case '%':

+						buf[i] = '%';

+						break;

+					default:

+						buf[i] = '%';

+						j--;

+						break;

+					}

+

+					j++;

+				}

+				break;

+			default:

+				{

+					buf[i] = cmd[j];

+				}

+				break;

+			}

+

+			j++;

+			i++;

+		}

+

+		buf[i] = 0;

+

+		if (occur)

+			strcpy (cmd, buf);

+

+		free (buf);

+	}

+}

+

+void xchat_globally_away(TCHAR *tszAway)

+{

+	char szTemp[512];

+	char szAway[512];

+

+	ConvertString(tszAway, szAway, 512);

+	_snprintf(szTemp, 512, "ALLSERV AWAY %s\0", szAway);

+	check_special_chars(szTemp);

+	xchat_exec(szTemp);

+}

+

+void xchat_away(TCHAR *tszAway)

+{

+	char szTemp[512];

+	char szAway[512];

+

+	ConvertString(tszAway, szAway, 512);

+	_snprintf(szTemp, 512, szAway);

+	check_special_chars(szTemp);

+	xchat_commandf(ph, "AWAY %s\0", szTemp);

+}

+

+void xchat_globally_back()

+{

+	std::vector<int> xs;

+	std::vector<int>::iterator xsi;

+	xchat_list *xl = xchat_list_get(ph, "channels");

+

+	if(xl)

+	{

+		while(xchat_list_next(ph, xl))

+		{

+			xsi = std::find(xs.begin(), xs.end(), xchat_list_int(ph, xl, "id"));

+

+			if((xsi == xs.end()) &&

+				((strlen(xchat_list_str(ph, xl, "server")) > 0) || 

+				(strlen(xchat_list_str(ph, xl, "channel")) > 0)))

+			{

+				xs.push_back(xchat_list_int(ph, xl, "id"));

+				xchat_set_context(ph, (xchat_context *)xchat_list_str(ph, xl, "context"));

+				xchat_back();

+			}

+		}

+

+		xchat_list_free(ph, xl);

+	}

+}

+

+

+

+void xchat_back()

+{

+	if(xchat_get_info(ph, "away"))

+	{

+		xchat_command(ph, "BACK");

+	}

+}

+

+HMENU setServerMenu()

+{

+	HMENU sTemp = CreateMenu();

+	TCHAR wszServer[128];

+	TCHAR wszNick[128];

+	TCHAR wszMenuEntry[256];

+

+	std::vector<int> xs;

+	std::vector<int>::iterator xsi;

+	xchat_list *xl = xchat_list_get(ph, "channels");

+

+	AppendMenu(sTemp, MF_STRING, ACT_AWAY, _T("Set Globally Away"));

+	AppendMenu(sTemp, MF_STRING, ACT_BACK, _T("Set Globally Back"));

+	AppendMenu(sTemp, MF_SEPARATOR, 0, NULL);

+

+	if(xl)

+	{

+		while(xchat_list_next(ph, xl))

+		{

+			xsi = std::find(xs.begin(), xs.end(), xchat_list_int(ph, xl, "id"));

+

+			if( (xsi == xs.end()) &&

+				((strlen(xchat_list_str(ph, xl, "server")) > 0) || 

+				(strlen(xchat_list_str(ph, xl, "channel")) > 0)))

+			{

+				xchat_set_context(ph, (xchat_context *)xchat_list_str(ph, xl, "context"));

+				xs.push_back(xchat_list_int(ph, xl, "id"));

+

+				char *network	= _strdup(xchat_list_str(ph, xl, "network"));

+				char *server	= _strdup(xchat_list_str(ph, xl, "server"));

+				char *nick		= _strdup(xchat_get_info(ph, "nick"));

+

+				if(network != NULL)

+				{

+					ConvertString(network, wszServer, 128);

+				}

+				else

+				{

+					ConvertString(server, wszServer, 128);

+				}

+

+				if(server != NULL)

+				{

+					ConvertString(nick, wszNick, 128);

+					_sntprintf(wszMenuEntry, 256, _T("%s @ %s\0"), wszNick, wszServer);

+

+					if(!xchat_get_info(ph, "away"))

+					{

+						AppendMenu(sTemp, MF_STRING, (xchat_list_int(ph, xl, "id") + 1), wszMenuEntry);

+					}

+					else

+					{

+						AppendMenu(sTemp, (MF_CHECKED | MF_STRING), (xchat_list_int(ph, xl, "id") + 1), wszMenuEntry);							

+					}

+				}

+

+				free(network);

+				free(server);

+				free(nick);

+			}

+		}

+

+		xchat_list_free(ph, xl);

+	}

+

+	return sTemp;

+}

+

+struct _xchat_context *xchat_find_server(int find_id)

+{

+	xchat_context *xc;

+	xchat_list *xl = xchat_list_get(ph, "channels");

+	int id;

+

+	if(!xl)

+		return NULL;

+

+	while(xchat_list_next(ph, xl))

+	{

+		id = xchat_list_int(ph, xl, "id");

+		

+		if(id == -1)

+		{

+			return NULL;

+		}

+		else if(id == find_id)

+		{

+			xc = (xchat_context *)xchat_list_str(ph, xl, "context");

+			

+			xchat_list_free(ph, xl);

+

+			return xc;

+		}

+	}

+

+	xchat_list_free(ph, xl);

+

+	return NULL;

+}

+

+void xchat_exec(char *command)

+{

+	xchat_set_context(ph, xchat_find_context(ph, NULL, NULL));

+	xchat_command(ph, command);

+}
\ No newline at end of file
diff --git a/plugins/xtray/xchat.h b/plugins/xtray/xchat.h
new file mode 100644
index 00000000..76452aeb
--- /dev/null
+++ b/plugins/xtray/xchat.h
@@ -0,0 +1,32 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _H_XCHAT_H

+#define _H_XCHAT_H

+

+void					xchat_exec			(char *);

+char					*xchat_strip_color	(char *);

+void					xchat_parse			(char *);

+struct _xchat_context	*xchat_find_server	(int);

+void					xchat_globally_away	(TCHAR *);

+void					xchat_away			(TCHAR *);

+void					xchat_globally_back	();

+void					xchat_back			();

+HMENU					setServerMenu		();

+

+#endif
\ No newline at end of file
diff --git a/plugins/xtray/xtray.cpp b/plugins/xtray/xtray.cpp
new file mode 100644
index 00000000..33ce125f
--- /dev/null
+++ b/plugins/xtray/xtray.cpp
@@ -0,0 +1,219 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#define _WIN32_IE 0x0601

+

+#include <windows.h>

+#include <list>

+#include <string>

+#include <shobjidl.h>

+

+#include "xchat-plugin.h"

+#include "resource.h"

+#include "callbacks.h"

+#include "utility.h"

+#include "xtray.h"

+#include "sdTray.h"

+#include "sdAlerts.h"

+

+/*****************************************************/

+/**** Don't want to pollute the namespace do we? *****/

+/*****************************************************/

+std::list<xchat_hook *> g_vHooks;

+

+/*****************************************************/

+/************ Global Identifiers *********************/

+/*****************************************************/

+WNDPROC g_hOldProc;

+xchat_plugin *ph;

+

+/*****************************************************/

+/***************** Resources *************************/

+/*****************************************************/

+HWND	g_hXchatWnd;

+HWND	g_hHotkeyWnd;

+HWND	g_hPrefDlg;

+HMENU	g_hTrayMenu;

+HICON	g_hIcons[11];

+HANDLE	g_hInstance;

+/*****************************************************/

+/***************** Preferences ***********************/

+/*****************************************************/

+unsigned int g_dwPrefs;

+TCHAR	g_szAway[512];

+int		g_iTime;

+

+

+BOOL WINAPI DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpVoid)

+{

+	if((fdwReason == DLL_PROCESS_ATTACH) || (fdwReason == DLL_THREAD_ATTACH))

+	{

+		g_hInstance = hModule;

+	}

+

+	return TRUE;

+}

+

+int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)

+{

+	ph = plugin_handle;

+

+	*plugin_name	= "X-Tray";

+	*plugin_desc	= "Minimize XChat to the Windows system tray";

+	*plugin_version = "1.2.4";

+

+	/***************************************************************************************************************************/

+	/************************* Load our preferances from xTray.ini *************************************************************/

+	/***************************************************************************************************************************/

+	LoadPrefs();

+

+	/***************************************************************************************************************************/

+	/************************* Finds the xChat window and saves it for later use ***********************************************/

+	/***************************************************************************************************************************/

+	g_hXchatWnd = (HWND)xchat_get_info(ph, "win_ptr");

+

+	if(g_hXchatWnd == NULL)

+	{

+		EnumThreadWindows(GetCurrentThreadId(), EnumWindowsProc, 0);

+	}

+

+	g_hOldProc	= (WNDPROC)GetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC);

+	SetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc);

+

+	/***************************************************************************************************************************/	

+	/************************* Grab the xChat Icon, Load our menu, create the window to receive the hotkey messages  ***********/

+	/************************* and register the windows message so we know if explorer crashes                       ***********/

+	/***************************************************************************************************************************/

+	g_hTrayMenu		= GetSubMenu(LoadMenu((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDR_TRAY_MENU)), 0);

+	g_hHotkeyWnd	= CreateDialog((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDD_ALERT), NULL,		(DLGPROC)HotKeyProc);

+	g_hPrefDlg		= CreateDialog((HINSTANCE)g_hInstance, MAKEINTRESOURCE(IDD_PREF),  g_hXchatWnd, (DLGPROC)PrefProc);

+

+	g_hIcons[0]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_XCHAT),			IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[1]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_CHANMSG),		IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[2]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_HIGHLIGHT),		IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[5]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_BANNED),			IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[6]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_KICKED),			IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[8]	= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_PMSG),			IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[10]= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_SNOTICE),		IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+	g_hIcons[11]= (HICON)LoadImage((HINSTANCE)g_hInstance, MAKEINTRESOURCE(ICO_DISCONNECTED),	IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

+

+	/***************************************************************************************************************************/

+	/************************* Add our icon to the tray ************************************************************************/

+	/***************************************************************************************************************************/

+	char szVersion[64];

+	_snprintf(szVersion, 64, "XChat-WDK [%s]", xchat_get_info(ph, "version"));

+	AddIcon(g_hXchatWnd, 1, g_hIcons[0], szVersion, (NIF_ICON | NIF_MESSAGE | NIF_TIP), WM_TRAYMSG);

+

+	/***************************************************************************************************************************/

+	/***************************************************************************************************************************/

+	/***************************************************************************************************************************/

+	if(g_dwPrefs & (1<<PREF_DNSIT))

+	{

+		DWORD dwStyle;

+		dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE);

+		dwStyle |= (1<<WS_CHILD);

+		SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle);

+		SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, (LONG_PTR)g_hHotkeyWnd);

+	}

+

+	/***************************************************************************************************************************/

+	/************************* Set our hooks and save them for later so we can unhook them *************************************/

+	/***************************************************************************************************************************/

+	g_vHooks.push_back(xchat_hook_print(ph, "Channel Msg Hilight",			XCHAT_PRI_NORM, event_cb,	(void *)CHAN_HILIGHT));

+	g_vHooks.push_back(xchat_hook_print(ph, "Channel Message",				XCHAT_PRI_NORM, event_cb,	(void *)CHAN_MESSAGE));

+	g_vHooks.push_back(xchat_hook_print(ph, "Topic Change",					XCHAT_PRI_NORM, event_cb,	(void *)CHAN_TOPIC_CHANGE));

+	g_vHooks.push_back(xchat_hook_print(ph, "Channel Action Hilight",		XCHAT_PRI_NORM, event_cb,	(void *)CHAN_HILIGHT));

+	g_vHooks.push_back(xchat_hook_print(ph, "Channel INVITE",				XCHAT_PRI_NORM, event_cb,	(void *)CHAN_INVITE));

+	g_vHooks.push_back(xchat_hook_print(ph, "You Kicked",					XCHAT_PRI_NORM, event_cb,	(void *)CHAN_KICKED));

+	g_vHooks.push_back(xchat_hook_print(ph, "Banned",						XCHAT_PRI_NORM, event_cb,	(void *)CHAN_BANNED));

+	g_vHooks.push_back(xchat_hook_print(ph, "CTCP Generic",					XCHAT_PRI_NORM, event_cb,	(void *)CTCP_GENERIC));

+	g_vHooks.push_back(xchat_hook_print(ph, "Private Message",				XCHAT_PRI_NORM, event_cb,	(void *)PMSG_RECEIVE));

+	g_vHooks.push_back(xchat_hook_print(ph, "Private Message to Dialog",	XCHAT_PRI_NORM, event_cb,	(void *)PMSG_RECEIVE));

+	g_vHooks.push_back(xchat_hook_print(ph, "Disconnected",					XCHAT_PRI_NORM, event_cb,	(void *)SERV_DISCONNECT));

+	g_vHooks.push_back(xchat_hook_print(ph, "Killed",						XCHAT_PRI_NORM, event_cb,	(void *)SERV_KILLED));

+	g_vHooks.push_back(xchat_hook_print(ph, "Notice",						XCHAT_PRI_NORM, event_cb,	(void *)SERV_NOTICE));

+	g_vHooks.push_back(xchat_hook_command(ph, "tray_alert",					XCHAT_PRI_NORM, command_cb,	"Create an Alert", NULL));

+

+	return 1;

+}

+

+int xchat_plugin_deinit(xchat_plugin *plugin_handle)

+{

+	/******************************************/

+	/****** Remove the Icon from the tray *****/

+	/******************************************/

+	StopBlink(g_hXchatWnd, 1, g_hIcons[0]);

+	RemoveIcon(g_hXchatWnd, 1);

+	

+	/*******************************************/

+	/*******************************************/

+	/*******************************************/

+	if(g_dwPrefs & (1<<PREF_DNSIT))

+	{

+		DWORD dwStyle;

+		dwStyle = GetWindowLong(g_hXchatWnd, GWL_STYLE);

+		dwStyle &= ~(1<<WS_CHILD);

+		SetWindowLongPtr(g_hXchatWnd, GWL_STYLE, (LONG_PTR)dwStyle);

+		SetWindowLongPtr(g_hXchatWnd, GWL_HWNDPARENT, NULL);

+	}

+

+	/******************************************/

+	/****** Unload our resources **************/

+	/******************************************/

+	DestroyMenu(g_hTrayMenu);

+

+	for(int i = 0; i <= 11; i++)

+	{

+		DestroyIcon(g_hIcons[i]);

+	}

+

+	/******************************************/

+	/****** Remove our window hook ************/

+	/******************************************/

+	SetWindowLongPtr(g_hXchatWnd, GWLP_WNDPROC, (LONG_PTR)g_hOldProc);

+

+	/******************************************/

+	/****** Remove our hotkey, and destroy ****/

+	/****** the window that receives its   ****/

+	/****** messages                       ****/

+	/******************************************/

+	UnregisterHotKey(g_hHotkeyWnd, 1);

+	DestroyWindow(g_hHotkeyWnd);

+	DestroyWindow(g_hPrefDlg);

+

+	/******************************************/

+	/************* Clean up Isle 7 ************/

+	/******************************************/

+	if(sdAlertNum())

+	{

+		sdCloseAlerts();

+	}

+	/******************************************/

+	/****** remove our xchat_hook_*s **********/

+	/******************************************/

+	while(!g_vHooks.empty())

+	{

+		if(g_vHooks.back() != NULL)

+		{

+			xchat_unhook(ph, g_vHooks.back());

+		}

+		g_vHooks.pop_back();

+	}

+

+	return 1;

+}

diff --git a/plugins/xtray/xtray.h b/plugins/xtray/xtray.h
new file mode 100644
index 00000000..56323cf2
--- /dev/null
+++ b/plugins/xtray/xtray.h
@@ -0,0 +1,77 @@
+/* X-Tray

+ * Copyright (C) 2005 Michael Hotaling <Mike.Hotaling@SinisterDevelopments.com>

+ *

+ * X-Tray 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.

+ * 

+ * X-Tray 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 X-Tray; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef _XTRAY_H

+#define _XTRAY_H

+

+/******************** Globals *************************/

+extern HWND				g_hXchatWnd;

+extern HWND				g_hHotkeyWnd;

+extern HWND				g_hPrefDlg;

+extern HMENU			g_hTrayMenu;

+extern HICON			g_hIcons[11];

+extern HANDLE			g_hInstance;

+extern unsigned int		g_dwPrefs;

+extern TCHAR			g_szAway[512];

+extern int				g_iTime;

+extern WNDPROC			g_hOldProc;

+extern struct _xchat_plugin *ph;

+/******************************************************/

+

+/******************** Messages ************************/

+#define WM_TRAYMSG WM_APP

+/******************************************************/

+

+/********************* Events *************************/

+#define CHAN_HILIGHT			1

+#define CHAN_INVITE				2

+#define CHAN_TOPIC_CHANGE		3

+#define CHAN_BANNED				4

+#define CHAN_KICKED				5

+

+#define CTCP_GENERIC			6

+#define PMSG_RECEIVE			7

+

+#define SERV_KILLED				8

+#define SERV_NOTICE				9

+#define SERV_DISCONNECT			10

+

+/* new events */

+#define CHAN_MESSAGE			21

+

+#define PREF_AOM				11 // away on minimize

+#define PREF_TOT				12 // Tray on Taskbar

+#define PREF_AMAE				13 // alert me about events

+#define PREF_OSBWM				14 // Only Show Balloon When Minimized

+#define PREF_UWIOB				15 // Use Window Instead of Balloon

+#define PREF_KAOI				16 // Keep alerts open indefinately

+#define PREF_MIOC				17 // Minimize instead of close

+#define PREF_BLINK				18 // blink icon

+#define PREF_CICO				19 // change icon - not implemented

+#define PREF_DNSIT				20 // Do not show in taskbar

+/******************************************************/

+#endif

+

+#ifdef _WIN64

+/* use replacement with the same value, and use SetWindowLongPtr instead

+   of SetWindowLong. more info:

+

+   http://msdn.microsoft.com/en-us/library/ms633591.aspx

+   http://msdn.microsoft.com/en-us/library/ms644898.aspx */

+#define GWL_HWNDPARENT GWLP_HWNDPARENT

+#endif