summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rwxr-xr-xautogen.sh4
-rw-r--r--configure.ac5
-rw-r--r--plugins/checksum/checksum.vcxproj2
-rw-r--r--plugins/dns/dns.vcxproj2
-rw-r--r--plugins/doat/doat.vcxproj2
-rw-r--r--plugins/exec/exec.vcxproj2
-rw-r--r--plugins/fishlim/fishlim.vcxproj2
-rw-r--r--plugins/hextray/hextray.vcxproj2
-rw-r--r--plugins/mpcinfo/mpcinfo.vcxproj2
-rw-r--r--plugins/perl/perl.vcxproj2
-rw-r--r--plugins/python/python.c423
-rw-r--r--plugins/python/python2.vcxproj2
-rw-r--r--plugins/python/python3.vcxproj2
-rw-r--r--plugins/sysinfo/sysinfo.vcxproj2
-rw-r--r--plugins/upd/upd.c80
-rw-r--r--plugins/upd/upd.vcxproj2
-rw-r--r--plugins/winamp/winamp.vcxproj2
-rw-r--r--src/common/common.vcxproj2
-rw-r--r--src/common/dcc.c12
-rw-r--r--src/common/dcc.h1
-rw-r--r--src/common/hexchat-plugin.h50
-rw-r--r--src/common/make-te.vcxproj2
-rw-r--r--src/common/outbound.c18
-rw-r--r--src/common/plugin.c144
-rw-r--r--src/common/plugin.h25
-rw-r--r--src/common/proto-irc.c21
-rw-r--r--src/common/servlist.c9
-rw-r--r--src/common/text.c12
-rw-r--r--src/common/text.h3
-rw-r--r--src/common/url.c243
-rw-r--r--src/fe-gtk/dccgui.c74
-rw-r--r--src/fe-gtk/fe-gtk.c14
-rw-r--r--src/fe-gtk/fe-gtk.vcxproj2
-rw-r--r--src/fe-gtk/fkeys.c32
-rw-r--r--src/fe-gtk/joind.c8
-rw-r--r--src/fe-gtk/menu.c2
-rw-r--r--src/fe-text/fe-text.vcxproj2
-rw-r--r--src/pixmaps/pixmaps.vcxproj2
-rw-r--r--src/version-script5
-rw-r--r--src/version/version.vcxproj2
-rw-r--r--win32/copy/copy.vcxproj2
-rw-r--r--win32/hexchat.props5
-rw-r--r--win32/installer/installer.vcxproj2
-rw-r--r--win32/nls/nls.vcxproj2
45 files changed, 926 insertions, 310 deletions
diff --git a/Makefile.am b/Makefile.am
index 073fd4b2..41e95375 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
+ACLOCAL_AMFLAGS = -I m4
+
 SUBDIRS = po intl src plugins man share
 
 EXTRA_DIST = autogen.sh
diff --git a/autogen.sh b/autogen.sh
index 7a640a56..607aa949 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -78,7 +78,7 @@ if test "$?" != "0"; then
 	exit 2
 fi
 echo running libtoolize...
-libtoolize --force
+libtoolize --copy --force --install
 if test "$?" != "0"; then
 	echo libtoolize failed, stopping.
 	exit 3
@@ -90,7 +90,7 @@ if test "$?" != "0"; then
 	exit 4
 fi
 echo running $AUTOMAKE...
-$AUTOMAKE -a
+$AUTOMAKE -a -c
 if test "$?" != "0"; then
 	echo automake failed, stopping.
 	exit 5
diff --git a/configure.ac b/configure.ac
index 7e385aef..009ae66a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,8 +8,9 @@ AC_COPYRIGHT([Copyright (C) 1998-2010 Peter Zelezny])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_SRCDIR([configure.ac])
 
-AM_INIT_AUTOMAKE([1.11 dist-bzip2 subdir-objects no-define foreign])
+AC_CONFIG_MACRO_DIR([m4])
 
+AM_INIT_AUTOMAKE([1.11 dist-bzip2 subdir-objects no-define foreign])
 AM_SILENT_RULES([yes])
 
 AC_USE_SYSTEM_EXTENSIONS
@@ -169,7 +170,7 @@ AC_ARG_ENABLE(shm,
 
 AC_ARG_ENABLE(spell,
 	[AS_HELP_STRING([--enable-spell=type],[enable spelling type: none static libsexy gtkspell])],
-		  spell=$enableval, spell=static)
+		  spell=$enableval, spell=libsexy)
 
 AC_ARG_ENABLE(ntlm,
 	[AS_HELP_STRING([--enable-ntlm],[enable Microsoft\'s NTLM auth (libntlm) library support (default: no)])],
diff --git a/plugins/checksum/checksum.vcxproj b/plugins/checksum/checksum.vcxproj
index 4090675c..ce75d68b 100644
--- a/plugins/checksum/checksum.vcxproj
+++ b/plugins/checksum/checksum.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/dns/dns.vcxproj b/plugins/dns/dns.vcxproj
index 39e47f67..f34c7bc3 100644
--- a/plugins/dns/dns.vcxproj
+++ b/plugins/dns/dns.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DNS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/doat/doat.vcxproj b/plugins/doat/doat.vcxproj
index bb44030d..32ac7055 100644
--- a/plugins/doat/doat.vcxproj
+++ b/plugins/doat/doat.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -78,7 +77,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;DOAT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/exec/exec.vcxproj b/plugins/exec/exec.vcxproj
index f1710119..e789767f 100644
--- a/plugins/exec/exec.vcxproj
+++ b/plugins/exec/exec.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -78,7 +77,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;EXEC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/fishlim/fishlim.vcxproj b/plugins/fishlim/fishlim.vcxproj
index 3743057c..d21c21ad 100644
--- a/plugins/fishlim/fishlim.vcxproj
+++ b/plugins/fishlim/fishlim.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/hextray/hextray.vcxproj b/plugins/hextray/hextray.vcxproj
index 9cac1368..3c48e9d0 100644
--- a/plugins/hextray/hextray.vcxproj
+++ b/plugins/hextray/hextray.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;XTRAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -78,7 +77,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;XTRAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/mpcinfo/mpcinfo.vcxproj b/plugins/mpcinfo/mpcinfo.vcxproj
index a63962a9..756fddf2 100644
--- a/plugins/mpcinfo/mpcinfo.vcxproj
+++ b/plugins/mpcinfo/mpcinfo.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -78,7 +77,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;MPCINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/perl/perl.vcxproj b/plugins/perl/perl.vcxproj
index af173966..afaaa08f 100644
--- a/plugins/perl/perl.vcxproj
+++ b/plugins/perl/perl.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -89,7 +88,6 @@ move xchat.pm.h "$(IntDir)"</Command>
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PERL518_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/python/python.c b/plugins/python/python.c
index b34ed0a9..ade5de95 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -72,15 +72,32 @@
 #include <structmember.h>
 #include <pythread.h>
 
+/* Macros to convert version macros into string literals.
+ * The indirect macro is a well-known preprocessor trick to force X to be evaluated before the # operator acts to make it a string literal.
+ * If STRINGIZE were to be directly defined as #X instead, VERSION would be "VERSION_MAJOR" instead of "1".
+ */
+#define STRINGIZE2(X) #X
+#define STRINGIZE(X) STRINGIZE2(X)
+
+/* Version number macros */
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 0
 
-#if PY_MAJOR_VERSION == 2
+/* Version string macro */
 #ifdef WIN32
-#undef WITH_THREAD
-#define VERSION "1.0/2.7"	/* Linked to python27.dll */
+#if PY_MAJOR_VERSION == 2
+#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "/2.7"	/* Linked to python27.dll */
+#elif PY_MAJOR_VERSION == 3
+#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "/3.3"	/* Linked to python33.dll */
+#endif
+#endif
+
+#ifndef VERSION
+#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR)
 #endif
 
+/* #define's for Python 2 */
+#if PY_MAJOR_VERSION == 2
 #undef PyLong_Check
 #define PyLong_Check PyInt_Check
 #define PyLong_AsLong PyInt_AsLong
@@ -95,15 +112,14 @@
 #define PyUnicode_FromString PyString_FromString
 #define PyUnicode_AsUTF8 PyString_AsString
 
-#else
-#define IS_PY3K
 #ifdef WIN32
-#define VERSION "1.0/3.3"	/* Linked to python33.dll */
+#undef WITH_THREAD
 #endif
 #endif
 
-#ifndef VERSION
-#define VERSION "1.0"
+/* #define for Python 3 */
+#if PY_MAJOR_VERSION == 3
+#define IS_PY3K
 #endif
 
 #define NONE 0
@@ -211,7 +227,8 @@ static PyThreadState *pTempThread;
 	((PluginObject *)(x))->gui = (y);
 
 #define HOOK_XCHAT  1
-#define HOOK_UNLOAD 2
+#define HOOK_XCHAT_ATTR 2
+#define HOOK_UNLOAD 3
 
 /* ===================================================================== */
 /* Object definitions */
@@ -228,6 +245,11 @@ typedef struct {
 
 typedef struct {
 	PyObject_HEAD
+	PyObject *time;
+} AttributeObject;
+
+typedef struct {
+	PyObject_HEAD
 	const char *listname;
 	PyObject *dict;
 } ListItemObject;
@@ -261,7 +283,9 @@ static PyObject *Util_BuildList(char *word[]);
 static void Util_Autoload();
 static char *Util_Expand(char *filename);
 
+static int Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata);
 static int Callback_Command(char *word[], char *word_eol[], void *userdata);
+static int Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata);
 static int Callback_Print(char *word[], void *userdata);
 static int Callback_Timer(void *userdata);
 static int Callback_ThreadTimer(void *userdata);
@@ -270,6 +294,8 @@ static PyObject *XChatOut_New();
 static PyObject *XChatOut_write(PyObject *self, PyObject *args);
 static void XChatOut_dealloc(PyObject *self);
 
+static PyObject *Attribute_New(hexchat_event_attrs *attrs);
+
 static void Context_dealloc(PyObject *self);
 static PyObject *Context_set(ContextObject *self, PyObject *args);
 static PyObject *Context_command(ContextObject *self, PyObject *args);
@@ -331,6 +357,7 @@ static PyTypeObject Plugin_Type;
 static PyTypeObject XChatOut_Type;
 static PyTypeObject Context_Type;
 static PyTypeObject ListItem_Type;
+static PyTypeObject Attribute_Type;
 
 static PyThreadState *main_tstate = NULL;
 static void *thread_timer = NULL;
@@ -488,6 +515,58 @@ Util_ReleaseThread(PyThreadState *tstate)
  * the load function, and the hooks for interactive interpreter. */
 
 static int
+Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
+{
+	Hook *hook = (Hook *) userdata;
+	PyObject *retobj;
+	PyObject *word_list, *word_eol_list;
+	PyObject *attributes;
+	int ret = 0;
+	PyObject *plugin;
+
+	plugin = hook->plugin;
+	BEGIN_PLUGIN(plugin);
+
+	word_list = Util_BuildList(word+1);
+	if (word_list == NULL) {
+		END_PLUGIN(plugin);
+		return 0;
+	}
+	word_eol_list = Util_BuildList(word_eol+1);
+	if (word_eol_list == NULL) {
+		Py_DECREF(word_list);
+		END_PLUGIN(plugin);
+		return 0;
+	}
+
+	attributes = Attribute_New(attrs);
+
+	if (hook->type == HOOK_XCHAT_ATTR)
+		retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list,
+					       word_eol_list, hook->userdata, attributes);
+	else
+		retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
+					       word_eol_list, hook->userdata);
+	Py_DECREF(word_list);
+	Py_DECREF(word_eol_list);
+	Py_DECREF(attributes);
+
+	if (retobj == Py_None) {
+		ret = HEXCHAT_EAT_NONE;
+		Py_DECREF(retobj);
+	} else if (retobj) {
+		ret = PyLong_AsLong(retobj);
+		Py_DECREF(retobj);
+	} else {
+		PyErr_Print();
+	}
+
+	END_PLUGIN(plugin);
+
+	return ret;
+}
+
+static int
 Callback_Command(char *word[], char *word_eol[], void *userdata)
 {
 	Hook *hook = (Hook *) userdata;
@@ -531,7 +610,96 @@ Callback_Command(char *word[], char *word_eol[], void *userdata)
 	return ret;
 }
 
-/* No Callback_Server() here. We use Callback_Command() as well. */
+static int
+Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata)
+{
+	Hook *hook = (Hook *) userdata;
+	PyObject *retobj;
+	PyObject *word_list;
+	PyObject *word_eol_list;
+	PyObject *attributes;
+	char **word_eol;
+	char *word_eol_raw;
+	int listsize = 0;
+	int next = 0;
+	int i;
+	int ret = 0;
+	PyObject *plugin;
+
+	/* Cut off the message identifier. */
+	word += 1;
+
+	/* HexChat doesn't provide a word_eol for print events, so we
+	 * build our own here. */
+	while (word[listsize] && word[listsize][0])
+		listsize++;
+	word_eol = (char **) g_malloc(sizeof(char*)*(listsize+1));
+	if (word_eol == NULL) {
+		hexchat_print(ph, "Not enough memory to alloc word_eol "
+				"for python plugin callback.");
+		return 0;
+	}
+	/* First build a word clone, but NULL terminated. */
+	memcpy(word_eol, word, listsize*sizeof(char*));
+	word_eol[listsize] = NULL;
+	/* Then join it. */
+	word_eol_raw = g_strjoinv(" ", word_eol);
+	if (word_eol_raw == NULL) {
+		hexchat_print(ph, "Not enough memory to alloc word_eol_raw "
+				"for python plugin callback.");
+		return 0;
+	}
+	/* And rebuild the real word_eol. */
+	for (i = 0; i != listsize; i++) {
+		word_eol[i] = word_eol_raw+next;
+		next += strlen(word[i])+1;
+	}
+	word_eol[i] = "";
+
+	plugin = hook->plugin;
+	BEGIN_PLUGIN(plugin);
+
+	word_list = Util_BuildList(word);
+	if (word_list == NULL) {
+		g_free(word_eol_raw);
+		g_free(word_eol);
+		END_PLUGIN(plugin);
+		return 0;
+	}
+	word_eol_list = Util_BuildList(word_eol);
+	if (word_eol_list == NULL) {
+		g_free(word_eol_raw);
+		g_free(word_eol);
+		Py_DECREF(word_list);
+		END_PLUGIN(plugin);
+		return 0;
+	}
+
+	attributes = Attribute_New(attrs);
+
+	retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list,
+					    word_eol_list, hook->userdata, attributes);
+
+	Py_DECREF(word_list);
+	Py_DECREF(word_eol_list);
+	Py_DECREF(attributes);
+
+	g_free(word_eol_raw);
+	g_free(word_eol);
+	if (retobj == Py_None) {
+		ret = HEXCHAT_EAT_NONE;
+		Py_DECREF(retobj);
+	} else if (retobj) {
+		ret = PyLong_AsLong(retobj);
+		Py_DECREF(retobj);
+	} else {
+		PyErr_Print();
+	}
+
+	END_PLUGIN(plugin);
+
+	return ret;
+}
 
 static int
 Callback_Print(char *word[], void *userdata)
@@ -597,8 +765,10 @@ Callback_Print(char *word[], void *userdata)
 		return 0;
 	}
 
+
 	retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
-				       word_eol_list, hook->userdata);
+					       word_eol_list, hook->userdata);
+
 	Py_DECREF(word_list);
 	Py_DECREF(word_eol_list);
 
@@ -823,6 +993,85 @@ static PyTypeObject XChatOut_Type = {
 
 
 /* ===================================================================== */
+/* Attribute object */
+
+#undef OFF
+#define OFF(x) offsetof(AttributeObject, x)
+
+static PyMemberDef Attribute_members[] = {
+	{"time", T_OBJECT, OFF(time), 0},
+	{0}
+};
+
+static void
+Attribute_dealloc(PyObject *self)
+{
+	Py_DECREF(((AttributeObject*)self)->time);
+	Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyObject *
+Attribute_repr(PyObject *self)
+{
+	return PyUnicode_FromFormat("<Attribute object at %p>", self);
+}
+
+static PyTypeObject Attribute_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
+	"hexchat.Attribute",	/*tp_name*/
+	sizeof(AttributeObject),	/*tp_basicsize*/
+	0,			/*tp_itemsize*/
+	Attribute_dealloc,	/*tp_dealloc*/
+	0,			/*tp_print*/
+	0,			/*tp_getattr*/
+	0,			/*tp_setattr*/
+	0,			/*tp_compare*/
+	Attribute_repr,		/*tp_repr*/
+	0,			/*tp_as_number*/
+	0,			/*tp_as_sequence*/
+	0,			/*tp_as_mapping*/
+	0,			/*tp_hash*/
+        0,                      /*tp_call*/
+        0,                      /*tp_str*/
+        PyObject_GenericGetAttr,/*tp_getattro*/
+        PyObject_GenericSetAttr,/*tp_setattro*/
+        0,                      /*tp_as_buffer*/
+        Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+        0,                      /*tp_doc*/
+        0,                      /*tp_traverse*/
+        0,                      /*tp_clear*/
+        0,                      /*tp_richcompare*/
+        0,                      /*tp_weaklistoffset*/
+        0,                      /*tp_iter*/
+        0,                      /*tp_iternext*/
+        0,                      /*tp_methods*/
+        Attribute_members,		/*tp_members*/
+        0,                      /*tp_getset*/
+        0,                      /*tp_base*/
+        0,                      /*tp_dict*/
+        0,                      /*tp_descr_get*/
+        0,                      /*tp_descr_set*/
+        0,						/*tp_dictoffset*/
+        0,                      /*tp_init*/
+        PyType_GenericAlloc,    /*tp_alloc*/
+        PyType_GenericNew,      /*tp_new*/
+      	PyObject_Del,          /*tp_free*/
+        0,                      /*tp_is_gc*/
+};
+
+static PyObject *
+Attribute_New(hexchat_event_attrs *attrs)
+{
+	AttributeObject *attr;
+	attr = PyObject_New(AttributeObject, &Attribute_Type);
+	if (attr != NULL) {
+		attr->time = PyLong_FromLong((long)attrs->server_time_utc);
+	}
+	return (PyObject *) attr;
+}
+
+
+/* ===================================================================== */
 /* Context object */
 
 static void
@@ -869,22 +1118,31 @@ Context_prnt(ContextObject *self, PyObject *args)
 }
 
 static PyObject *
-Context_emit_print(ContextObject *self, PyObject *args)
+Context_emit_print(ContextObject *self, PyObject *args, PyObject *kwargs)
 {
-	char *argv[10];
+	char *argv[6];
 	char *name;
 	int res;
-	memset(&argv, 0, sizeof(char*)*10);
-	if (!PyArg_ParseTuple(args, "s|ssssss:print_event", &name,
+	long time = 0;
+	hexchat_event_attrs *attrs;
+	char *kwlist[] = {"name", "arg1", "arg2", "arg3",
+					"arg4", "arg5", "arg6", 
+					"time", NULL};
+	memset(&argv, 0, sizeof(char*)*6);
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ssssssl:print_event", kwlist, &name,
 			      &argv[0], &argv[1], &argv[2],
 			      &argv[3], &argv[4], &argv[5],
-			      &argv[6], &argv[7], &argv[8]))
+				  &time))
 		return NULL;
 	BEGIN_XCHAT_CALLS(ALLOW_THREADS);
 	hexchat_set_context(ph, self->context);
-	res = hexchat_emit_print(ph, name, argv[0], argv[1], argv[2],
-					 argv[3], argv[4], argv[5],
-					 argv[6], argv[7], argv[8]);
+	attrs = hexchat_event_attrs_create(ph);
+	attrs->server_time_utc = (time_t)time; 
+	
+	res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2],
+					 argv[3], argv[4], argv[5], NULL);
+
+	hexchat_event_attrs_free(ph, attrs);
 	END_XCHAT_CALLS();
 	return PyLong_FromLong(res);
 }
@@ -945,7 +1203,7 @@ static PyMethodDef Context_methods[] = {
 	{"set", (PyCFunction) Context_set, METH_NOARGS},
 	{"command", (PyCFunction) Context_command, METH_VARARGS},
 	{"prnt", (PyCFunction) Context_prnt, METH_VARARGS},
-	{"emit_print", (PyCFunction) Context_emit_print, METH_VARARGS},
+	{"emit_print", (PyCFunction) Context_emit_print, METH_VARARGS|METH_KEYWORDS},
 	{"get_info", (PyCFunction) Context_get_info, METH_VARARGS},
 	{"get_list", (PyCFunction) Context_get_list, METH_VARARGS},
 	{NULL, NULL}
@@ -1232,7 +1490,7 @@ Plugin_RemoveHook(PyObject *plugin, Hook *hook)
 	list = g_slist_find(Plugin_GetHooks(plugin), hook);
 	if (list) {
 		/* Ok, unhook it. */
-		if (hook->type == HOOK_XCHAT) {
+		if (hook->type != HOOK_UNLOAD) {
 			/* This is an xchat hook. Unregister it. */
 			BEGIN_XCHAT_CALLS(NONE);
 			hexchat_unhook(ph, (hexchat_hook*)hook->data);
@@ -1255,7 +1513,7 @@ Plugin_RemoveAllHooks(PyObject *plugin)
 	GSList *list = Plugin_GetHooks(plugin);
 	while (list) {
 		Hook *hook = (Hook *) list->data;
-		if (hook->type == HOOK_XCHAT) {
+		if (hook->type != HOOK_UNLOAD) {
 			/* This is an xchat hook. Unregister it. */
 			BEGIN_XCHAT_CALLS(NONE);
 			hexchat_unhook(ph, (hexchat_hook*)hook->data);
@@ -1511,21 +1769,30 @@ Module_xchat_prnt(PyObject *self, PyObject *args)
 }
 
 static PyObject *
-Module_hexchat_emit_print(PyObject *self, PyObject *args)
+Module_hexchat_emit_print(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-	char *argv[10];
+	char *argv[6];
 	char *name;
 	int res;
-	memset(&argv, 0, sizeof(char*)*10);
-	if (!PyArg_ParseTuple(args, "s|ssssss:print_event", &name,
+	long time = 0;
+	hexchat_event_attrs *attrs;
+	char *kwlist[] = {"name", "arg1", "arg2", "arg3",
+					"arg4", "arg5", "arg6", 
+					"time", NULL};
+	memset(&argv, 0, sizeof(char*)*6);
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ssssssl:print_event", kwlist, &name,
 			      &argv[0], &argv[1], &argv[2],
 			      &argv[3], &argv[4], &argv[5],
-			      &argv[6], &argv[7], &argv[8]))
+				  &time))
 		return NULL;
 	BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS);
-	res = hexchat_emit_print(ph, name, argv[0], argv[1], argv[2],
-					 argv[3], argv[4], argv[5],
-					 argv[6], argv[7], argv[8]);
+	attrs = hexchat_event_attrs_create(ph);
+	attrs->server_time_utc = (time_t)time; 
+	
+	res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2],
+					 argv[3], argv[4], argv[5], NULL);
+
+	hexchat_event_attrs_free(ph, attrs);
 	END_XCHAT_CALLS();
 	return PyLong_FromLong(res);
 }
@@ -1757,7 +2024,7 @@ Module_hexchat_hook_command(PyObject *self, PyObject *args, PyObject *kwargs)
 					       Callback_Command, help, hook);
 	END_XCHAT_CALLS();
 
-	return PyLong_FromLong((long)hook);
+	return PyLong_FromVoidPtr(hook);
 }
 
 static PyObject *
@@ -1789,11 +2056,47 @@ Module_hexchat_hook_server(PyObject *self, PyObject *args, PyObject *kwargs)
 		return NULL;
 
 	BEGIN_XCHAT_CALLS(NONE);
-	hook->data = (void*)hexchat_hook_server(ph, name, priority,
-					      Callback_Command, hook);
+	hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority,
+					      Callback_Server, hook);
+	END_XCHAT_CALLS();
+
+	return PyLong_FromVoidPtr(hook);
+}
+
+static PyObject *
+Module_hexchat_hook_server_attrs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	char *name;
+	PyObject *callback;
+	PyObject *userdata = Py_None;
+	int priority = HEXCHAT_PRI_NORM;
+	PyObject *plugin;
+	Hook *hook;
+	char *kwlist[] = {"name", "callback", "userdata", "priority", 0};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_server",
+					 kwlist, &name, &callback, &userdata,
+					 &priority))
+		return NULL;
+
+	plugin = Plugin_GetCurrent();
+	if (plugin == NULL)
+		return NULL;
+	if (!PyCallable_Check(callback)) {
+		PyErr_SetString(PyExc_TypeError, "callback is not callable");
+		return NULL;
+	}
+
+	hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, NULL, NULL);
+	if (hook == NULL)
+		return NULL;
+
+	BEGIN_XCHAT_CALLS(NONE);
+	hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority,
+					      Callback_Server, hook);
 	END_XCHAT_CALLS();
 
-	return PyLong_FromLong((long)hook);
+	return PyLong_FromVoidPtr(hook);
 }
 
 static PyObject *
@@ -1829,7 +2132,43 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs)
 					     Callback_Print, hook);
 	END_XCHAT_CALLS();
 
-	return PyLong_FromLong((long)hook);
+	return PyLong_FromVoidPtr(hook);
+}
+
+static PyObject *
+Module_hexchat_hook_print_attrs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	char *name;
+	PyObject *callback;
+	PyObject *userdata = Py_None;
+	int priority = HEXCHAT_PRI_NORM;
+	PyObject *plugin;
+	Hook *hook;
+	char *kwlist[] = {"name", "callback", "userdata", "priority", 0};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_print_attrs",
+					 kwlist, &name, &callback, &userdata,
+					 &priority))
+		return NULL;
+
+	plugin = Plugin_GetCurrent();
+	if (plugin == NULL)
+		return NULL;
+	if (!PyCallable_Check(callback)) {
+		PyErr_SetString(PyExc_TypeError, "callback is not callable");
+		return NULL;
+	}
+
+	hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, name, NULL);
+	if (hook == NULL)
+		return NULL;
+
+	BEGIN_XCHAT_CALLS(NONE);
+	hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority,
+					     Callback_Print_Attrs, hook);
+	END_XCHAT_CALLS();
+
+	return PyLong_FromVoidPtr(hook);
 }
 
 static PyObject *
@@ -1864,7 +2203,7 @@ Module_hexchat_hook_timer(PyObject *self, PyObject *args, PyObject *kwargs)
 					     Callback_Timer, hook);
 	END_XCHAT_CALLS();
 
-	return PyLong_FromLong((long)hook);
+	return PyLong_FromVoidPtr(hook);
 }
 
 static PyObject *
@@ -1892,7 +2231,7 @@ Module_hexchat_hook_unload(PyObject *self, PyObject *args, PyObject *kwargs)
 	if (hook == NULL)
 		return NULL;
 
-	return PyLong_FromLong((long)hook);
+	return PyLong_FromVoidPtr(hook);
 }
 
 static PyObject *
@@ -1918,7 +2257,7 @@ Module_hexchat_unhook(PyObject *self, PyObject *args)
 	}
 	else
 	{
-		hook = (Hook *)PyLong_AsLong(obj);
+		hook = (Hook *)PyLong_AsVoidPtr(obj);
 		Plugin_RemoveHook(plugin, hook);
 	}	
 
@@ -2066,8 +2405,8 @@ static PyMethodDef Module_xchat_methods[] = {
 		METH_VARARGS},
 	{"prnt",		Module_xchat_prnt,
 		METH_VARARGS},
-	{"emit_print",		Module_hexchat_emit_print,
-		METH_VARARGS},
+	{"emit_print",		(PyCFunction)Module_hexchat_emit_print,
+		METH_VARARGS|METH_KEYWORDS},
 	{"get_info",		Module_hexchat_get_info,
 		METH_VARARGS},
 	{"get_prefs",		Module_xchat_get_prefs,
@@ -2088,8 +2427,12 @@ static PyMethodDef Module_xchat_methods[] = {
 		METH_VARARGS|METH_KEYWORDS},
 	{"hook_server",		(PyCFunction)Module_hexchat_hook_server,
 		METH_VARARGS|METH_KEYWORDS},
+	{"hook_server_attrs",		(PyCFunction)Module_hexchat_hook_server_attrs,
+		METH_VARARGS|METH_KEYWORDS},
 	{"hook_print",		(PyCFunction)Module_hexchat_hook_print,
 		METH_VARARGS|METH_KEYWORDS},
+	{"hook_print_attrs",		(PyCFunction)Module_hexchat_hook_print_attrs,
+		METH_VARARGS|METH_KEYWORDS},
 	{"hook_timer",		(PyCFunction)Module_hexchat_hook_timer,
 		METH_VARARGS|METH_KEYWORDS},
 	{"hook_unload",		(PyCFunction)Module_hexchat_hook_unload,
diff --git a/plugins/python/python2.vcxproj b/plugins/python/python2.vcxproj
index 1f524134..6730f45e 100644
--- a/plugins/python/python2.vcxproj
+++ b/plugins/python/python2.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/python/python3.vcxproj b/plugins/python/python3.vcxproj
index ddf56132..28ffc80c 100644
--- a/plugins/python/python3.vcxproj
+++ b/plugins/python/python3.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/sysinfo/sysinfo.vcxproj b/plugins/sysinfo/sysinfo.vcxproj
index 0446e723..88c090cc 100644
--- a/plugins/sysinfo/sysinfo.vcxproj
+++ b/plugins/sysinfo/sysinfo.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -81,7 +80,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/upd/upd.c b/plugins/upd/upd.c
index 3ab8edd5..7ebf95bc 100644
--- a/plugins/upd/upd.c
+++ b/plugins/upd/upd.c
@@ -27,8 +27,9 @@
 
 #include "hexchat-plugin.h"
 
-#define DEFAULT_DELAY 10	/* 10 seconds */
+#define DEFAULT_DELAY 30	/* 30 seconds */
 #define DEFAULT_FREQ 360	/* 6 hours */
+#define DOWNLOAD_URL "http://dl.hexchat.net/hexchat"
 
 static hexchat_plugin *ph;   /* plugin handle */
 static char name[] = "Update Checker";
@@ -39,61 +40,6 @@ static const char upd_help[] = "Update Checker Usage:\n  /UPDCHK, check for HexC
 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,
-							"https://raw.github.com/hexchat/hexchat/master/win32/version.txt",
-							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);
-		if (strlen (buffer) == 5)
-			return buffer;
-		else
-			return "Unknown";
-	}
-
-	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"),
@@ -137,7 +83,11 @@ check_version ()
 	else
 	{
 		static char buffer[1024];
+		char infobuffer[32];
+		int statuscode;
+
 		DWORD dwRead;
+		DWORD infolen = sizeof(infobuffer);
 
 		HttpAddRequestHeaders (hResource, TEXT ("Connection: close\r\n"), -1L, HTTP_ADDREQ_FLAG_ADD);	/* workaround for GC bug */
 		HttpSendRequest (hResource, NULL, 0, NULL, 0);
@@ -151,10 +101,18 @@ check_version ()
 			buffer[dwRead] = 0;
 		}
 
+		HttpQueryInfo(hResource,
+					HTTP_QUERY_STATUS_CODE,
+					&infobuffer,
+					&infolen,
+					NULL);
+
 		InternetCloseHandle (hResource);
 		InternetCloseHandle (hConnect);
 		InternetCloseHandle (hOpen);
-		if (strlen (buffer) == 5)
+
+		statuscode = atoi(infobuffer);
+		if (statuscode == 200)
 			return buffer;
 		else
 			return "Unknown";
@@ -233,9 +191,9 @@ print_version (char *word[], char *word_eol[], void *userdata)
 		else
 		{
 #ifdef _WIN64 /* use this approach, the wProcessorArchitecture method always returns 0 (=x86) for some reason */
-			hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\nhttp://dl.hexchat.org/hexchat/HexChat%%20%s%%20x64.exe\n", name, version);
+			hexchat_printf (ph, "%s:\tA HexChat update is available! You can download it from here:\n%s/HexChat%%20%s%%20x64.exe\n", name, DOWNLOAD_URL, version);
 #else
-			hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\nhttp://dl.hexchat.org/hexchat/HexChat%%20%s%%20x86.exe\n", name, version);
+			hexchat_printf (ph, "%s:\tA HexChat update is available! You can download it from here:\n%s/HexChat%%20%s%%20x86.exe\n", name, DOWNLOAD_URL, version);
 #endif
 		}
 		return HEXCHAT_EAT_HEXCHAT;
@@ -256,9 +214,9 @@ print_version_quiet (void *userdata)
 	if (!(strcmp (version, hexchat_get_info (ph, "version")) == 0) && !(strcmp (version, "Unknown") == 0))
 	{
 #ifdef _WIN64 /* use this approach, the wProcessorArchitecture method always returns 0 (=x86) for plugins for some reason */
-		hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\nhttps://github.com/downloads/hexchat/hexchat/HexChat%%20%s%%20x64.exe\n", name, version);
+		hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\n%s/HexChat%%20%s%%20x64.exe\n", name, DOWNLOAD_URL, version);
 #else
-		hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\nhttps://github.com/downloads/hexchat/hexchat/HexChat%%20%s%%20x86.exe\n", name, version);
+		hexchat_printf (ph, "%s\tA HexChat update is available! You can download it from here:\n%s/HexChat%%20%s%%20x86.exe\n", name, DOWNLOAD_URL, version);
 #endif
 		/* print update url once, then stop the timer */
 		return 0;
diff --git a/plugins/upd/upd.vcxproj b/plugins/upd/upd.vcxproj
index 1b3009dc..a06085b2 100644
--- a/plugins/upd/upd.vcxproj
+++ b/plugins/upd/upd.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;UPD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -80,7 +79,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;UPD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/plugins/winamp/winamp.vcxproj b/plugins/winamp/winamp.vcxproj
index 667ec598..e140f55f 100644
--- a/plugins/winamp/winamp.vcxproj
+++ b/plugins/winamp/winamp.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WINAMP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -78,7 +77,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;WINAMP_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index c71d6ced..5568409e 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -119,7 +119,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

@@ -137,7 +136,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

diff --git a/src/common/dcc.c b/src/common/dcc.c
index c0527510..5f4b1190 100644
--- a/src/common/dcc.c
+++ b/src/common/dcc.c
@@ -227,6 +227,15 @@ is_dcc (struct DCC *dcc)
 	return FALSE;
 }
 
+gboolean
+is_dcc_completed (struct DCC *dcc)
+{
+	if (dcc != NULL)
+		return (dcc->dccstat == STAT_FAILED || dcc->dccstat == STAT_DONE || dcc->dccstat == STAT_ABORTED);
+
+	return FALSE;
+}
+
 /* this is called from hexchat.c:hexchat_misc_checks() every 1 second. */
 
 void
@@ -548,7 +557,8 @@ dcc_chat_line (struct DCC *dcc, char *line)
 	for (i = 5; i < PDIWORDS; i++)
 		word[i] = "\000";
 
-	ret = plugin_emit_print (sess, word);
+	ret = plugin_emit_print (sess, word) 
+		+ plugin_emit_print_attrs (sess, word, 0);
 
 	/* did the plugin close it? */
 	if (!g_slist_find (dcc_list, dcc))
diff --git a/src/common/dcc.h b/src/common/dcc.h
index e3163c8a..acb87f34 100644
--- a/src/common/dcc.h
+++ b/src/common/dcc.h
@@ -117,6 +117,7 @@ struct dccstat_info
 extern struct dccstat_info dccstat[];
 
 gboolean is_dcc (struct DCC *dcc);
+gboolean is_dcc_completed (struct DCC *dcc);
 void dcc_abort (session *sess, struct DCC *dcc);
 void dcc_get (struct DCC *dcc);
 int dcc_resume (struct DCC *dcc);
diff --git a/src/common/hexchat-plugin.h b/src/common/hexchat-plugin.h
index 36dc544f..61597181 100644
--- a/src/common/hexchat-plugin.h
+++ b/src/common/hexchat-plugin.h
@@ -49,6 +49,10 @@ typedef struct _hexchat_hook hexchat_hook;
 #ifndef PLUGIN_C
 typedef struct _hexchat_context hexchat_context;
 #endif
+typedef struct
+{
+	time_t server_time_utc; /* 0 if not used */
+} hexchat_event_attrs;
 
 #ifndef PLUGIN_C
 struct _hexchat_plugin
@@ -164,6 +168,23 @@ struct _hexchat_plugin
 		const char *var);
 	int (*hexchat_pluginpref_list) (hexchat_plugin *ph,
 		char *dest);
+	hexchat_hook *(*hexchat_hook_server_attrs) (hexchat_plugin *ph,
+		   const char *name,
+		   int pri,
+		   int (*callback) (char *word[], char *word_eol[],
+							hexchat_event_attrs *attrs, void *user_data),
+		   void *userdata);
+	hexchat_hook *(*hexchat_hook_print_attrs) (hexchat_plugin *ph,
+		  const char *name,
+		  int pri,
+		  int (*callback) (char *word[], hexchat_event_attrs *attrs,
+						   void *user_data),
+		  void *userdata);
+	int (*hexchat_emit_print_attrs) (hexchat_plugin *ph, hexchat_event_attrs *attrs,
+									 const char *event_name, ...);
+	hexchat_event_attrs *(*hexchat_event_attrs_create) (hexchat_plugin *ph);
+	void (*hexchat_event_attrs_free) (hexchat_plugin *ph,
+									  hexchat_event_attrs *attrs);
 };
 #endif
 
@@ -176,6 +197,10 @@ hexchat_hook_command (hexchat_plugin *ph,
 		    const char *help_text,
 		    void *userdata);
 
+hexchat_event_attrs *hexchat_event_attrs_create (hexchat_plugin *ph);
+
+void hexchat_event_attrs_free (hexchat_plugin *ph, hexchat_event_attrs *attrs);
+
 hexchat_hook *
 hexchat_hook_server (hexchat_plugin *ph,
 		   const char *name,
@@ -184,6 +209,14 @@ hexchat_hook_server (hexchat_plugin *ph,
 		   void *userdata);
 
 hexchat_hook *
+hexchat_hook_server_attrs (hexchat_plugin *ph,
+		   const char *name,
+		   int pri,
+		   int (*callback) (char *word[], char *word_eol[],
+							hexchat_event_attrs *attrs, void *user_data),
+		   void *userdata);
+
+hexchat_hook *
 hexchat_hook_print (hexchat_plugin *ph,
 		  const char *name,
 		  int pri,
@@ -191,6 +224,14 @@ hexchat_hook_print (hexchat_plugin *ph,
 		  void *userdata);
 
 hexchat_hook *
+hexchat_hook_print_attrs (hexchat_plugin *ph,
+		  const char *name,
+		  int pri,
+		  int (*callback) (char *word[], hexchat_event_attrs *attrs,
+						   void *user_data),
+		  void *userdata);
+
+hexchat_hook *
 hexchat_hook_timer (hexchat_plugin *ph,
 		  int timeout,
 		  int (*callback) (void *user_data),
@@ -297,6 +338,10 @@ int
 hexchat_emit_print (hexchat_plugin *ph,
 		  const char *event_name, ...);
 
+int 
+hexchat_emit_print_attrs (hexchat_plugin *ph, hexchat_event_attrs *attrs,
+						  const char *event_name, ...);
+
 char *
 hexchat_gettext (hexchat_plugin *ph,
 	       const char *msgid);
@@ -350,8 +395,12 @@ hexchat_pluginpref_list (hexchat_plugin *ph,
 #define HEXCHAT_PLUGIN_HANDLE (ph)
 #endif
 #define hexchat_hook_command ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_command)
+#define hexchat_event_attrs_create ((HEXCHAT_PLUGIN_HANDLE)->hexchat_event_attrs_create)
+#define hexchat_event_attrs_free ((HEXCHAT_PLUGIN_HANDLE)->hexchat_event_attrs_free)
 #define hexchat_hook_server ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_server)
+#define hexchat_hook_server_attrs ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_server_attrs)
 #define hexchat_hook_print ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_print)
+#define hexchat_hook_print_attrs ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_print_attrs)
 #define hexchat_hook_timer ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_timer)
 #define hexchat_hook_fd ((HEXCHAT_PLUGIN_HANDLE)->hexchat_hook_fd)
 #define hexchat_unhook ((HEXCHAT_PLUGIN_HANDLE)->hexchat_unhook)
@@ -374,6 +423,7 @@ hexchat_pluginpref_list (hexchat_plugin *ph,
 #define hexchat_plugingui_add ((HEXCHAT_PLUGIN_HANDLE)->hexchat_plugingui_add)
 #define hexchat_plugingui_remove ((HEXCHAT_PLUGIN_HANDLE)->hexchat_plugingui_remove)
 #define hexchat_emit_print ((HEXCHAT_PLUGIN_HANDLE)->hexchat_emit_print)
+#define hexchat_emit_print_attrs ((HEXCHAT_PLUGIN_HANDLE)->hexchat_emit_print_attrs)
 #define hexchat_list_time ((HEXCHAT_PLUGIN_HANDLE)->hexchat_list_time)
 #define hexchat_gettext ((HEXCHAT_PLUGIN_HANDLE)->hexchat_gettext)
 #define hexchat_send_modes ((HEXCHAT_PLUGIN_HANDLE)->hexchat_send_modes)
diff --git a/src/common/make-te.vcxproj b/src/common/make-te.vcxproj
index 07bb5ca4..b9f0f11f 100644
--- a/src/common/make-te.vcxproj
+++ b/src/common/make-te.vcxproj
@@ -57,7 +57,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -77,7 +76,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/src/common/outbound.c b/src/common/outbound.c
index 6beaa2cc..91188a8a 100644
--- a/src/common/outbound.c
+++ b/src/common/outbound.c
@@ -487,19 +487,19 @@ create_mask (session * sess, char *mask, char *mode, char *typestr, int deop)
 			switch (type)
 			{
 			case 0:
-				snprintf (buf, sizeof (buf), "%s%s *!*@%s.*", mode, p2, domain);
+				snprintf (buf, sizeof (buf), "%s %s *!*@%s.*", mode, p2, domain);
 				break;
 
 			case 1:
-				snprintf (buf, sizeof (buf), "%s%s *!*@%s", mode, p2, fullhost);
+				snprintf (buf, sizeof (buf), "%s %s *!*@%s", mode, p2, fullhost);
 				break;
 
 			case 2:
-				snprintf (buf, sizeof (buf), "%s%s *!%s@%s.*", mode, p2, username, domain);
+				snprintf (buf, sizeof (buf), "%s %s *!%s@%s.*", mode, p2, username, domain);
 				break;
 
 			case 3:
-				snprintf (buf, sizeof (buf), "%s%s *!%s@%s", mode, p2, username, fullhost);
+				snprintf (buf, sizeof (buf), "%s %s *!%s@%s", mode, p2, username, fullhost);
 				break;
 			}
 		} else
@@ -507,19 +507,19 @@ create_mask (session * sess, char *mask, char *mode, char *typestr, int deop)
 			switch (type)
 			{
 			case 0:
-				snprintf (buf, sizeof (buf), "%s%s *!*@*%s", mode, p2, domain);
+				snprintf (buf, sizeof (buf), "%s %s *!*@*%s", mode, p2, domain);
 				break;
 
 			case 1:
-				snprintf (buf, sizeof (buf), "%s%s *!*@%s", mode, p2, fullhost);
+				snprintf (buf, sizeof (buf), "%s %s *!*@%s", mode, p2, fullhost);
 				break;
 
 			case 2:
-				snprintf (buf, sizeof (buf), "%s%s *!%s@*%s", mode, p2, username, domain);
+				snprintf (buf, sizeof (buf), "%s %s *!%s@*%s", mode, p2, username, domain);
 				break;
 
 			case 3:
-				snprintf (buf, sizeof (buf), "%s%s *!%s@%s", mode, p2, username, fullhost);
+				snprintf (buf, sizeof (buf), "%s %s *!%s@%s", mode, p2, username, fullhost);
 				break;
 			}
 		}
@@ -3877,7 +3877,7 @@ const struct commands xc_cmds[] = {
 	{"ME", cmd_me, 0, 0, 1,
 	 N_("ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps)")},
 	{"MENU", cmd_menu, 0, 0, 1, "MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command]\n"
-										 "       See http://docs.hexchat.org/en/latest/plugins.html#controlling-the-gui for more details."},
+										 "       See http://hexchat.readthedocs.org/en/latest/plugins.html#controlling-the-gui for more details."},
 	{"MKICK", cmd_mkick, 1, 1, 1,
 	 N_("MKICK, Mass kicks everyone except you in the current channel (needs chanop)")},
 	{"MODE", cmd_mode, 1, 0, 1, 0},
diff --git a/src/common/plugin.c b/src/common/plugin.c
index 5a6a42a6..50157ea1 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -86,6 +86,8 @@ struct _hexchat_list
 typedef int (hexchat_cmd_cb) (char *word[], char *word_eol[], void *user_data);
 typedef int (hexchat_serv_cb) (char *word[], char *word_eol[], void *user_data);
 typedef int (hexchat_print_cb) (char *word[], void *user_data);
+typedef int (hexchat_serv_attrs_cb) (char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *user_data);
+typedef int (hexchat_print_attrs_cb) (char *word[], hexchat_event_attrs *attrs, void *user_data);
 typedef int (hexchat_fd_cb) (int fd, int flags, void *user_data);
 typedef int (hexchat_timer_cb) (void *user_data);
 typedef int (hexchat_init_func) (hexchat_plugin *, char **, char **, char **, char *);
@@ -102,12 +104,14 @@ enum
 
 enum
 {
-	HOOK_COMMAND,	/* /command */
-	HOOK_SERVER,	/* PRIVMSG, NOTICE, numerics */
-	HOOK_PRINT,		/* All print events */
-	HOOK_TIMER,		/* timeouts */
-	HOOK_FD,			/* sockets & fds */
-	HOOK_DELETED	/* marked for deletion */
+	HOOK_COMMAND,      /* /command */
+	HOOK_SERVER,       /* PRIVMSG, NOTICE, numerics */
+	HOOK_SERVER_ATTRS, /* same as above, with attributes */
+	HOOK_PRINT,        /* All print events */
+	HOOK_PRINT_ATTRS,  /* same as above, with attributes */
+	HOOK_TIMER,        /* timeouts */
+	HOOK_FD,           /* sockets & fds */
+	HOOK_DELETED       /* marked for deletion */
 };
 
 GSList *plugin_list = NULL;	/* export for plugingui.c */
@@ -289,12 +293,11 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
 		pl->hexchat_pluginpref_get_int = hexchat_pluginpref_get_int;
 		pl->hexchat_pluginpref_delete = hexchat_pluginpref_delete;
 		pl->hexchat_pluginpref_list = hexchat_pluginpref_list;
-
-		/* incase new plugins are loaded on older HexChat */
-		pl->hexchat_dummy4 = hexchat_dummy;
-		pl->hexchat_dummy3 = hexchat_dummy;
-		pl->hexchat_dummy2 = hexchat_dummy;
-		pl->hexchat_dummy1 = hexchat_dummy;
+		pl->hexchat_hook_server_attrs = hexchat_hook_server_attrs;
+		pl->hexchat_hook_print_attrs = hexchat_hook_print_attrs;
+		pl->hexchat_emit_print_attrs = hexchat_emit_print_attrs;
+		pl->hexchat_event_attrs_create = hexchat_event_attrs_create;
+		pl->hexchat_event_attrs_free = hexchat_event_attrs_free;
 
 		/* run hexchat_plugin_init, if it returns 0, close the plugin */
 		if (((hexchat_init_func *)init_func) (pl, &pl->name, &pl->desc, &pl->version, arg) == 0)
@@ -519,7 +522,7 @@ plugin_hook_find (GSList *list, int type, char *name)
 	while (list)
 	{
 		hook = list->data;
-		if (hook->type == type)
+		if (hook && hook->type == type)
 		{
 			if (g_ascii_strcasecmp (hook->name, name) == 0)
 				return list;
@@ -539,7 +542,8 @@ plugin_hook_find (GSList *list, int type, char *name)
 /* check for plugin hooks and run them */
 
 static int
-plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[], int type)
+plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
+				 hexchat_event_attrs *attrs, int type)
 {
 	GSList *list, *next;
 	hexchat_hook *hook;
@@ -562,9 +566,15 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[], int
 		case HOOK_COMMAND:
 			ret = ((hexchat_cmd_cb *)hook->callback) (word, word_eol, hook->userdata);
 			break;
+		case HOOK_PRINT_ATTRS:
+			ret = ((hexchat_print_attrs_cb *)hook->callback) (word, attrs, hook->userdata);
+			break;
 		case HOOK_SERVER:
 			ret = ((hexchat_serv_cb *)hook->callback) (word, word_eol, hook->userdata);
 			break;
+		case HOOK_SERVER_ATTRS:
+			ret = ((hexchat_serv_attrs_cb *)hook->callback) (word, word_eol, attrs, hook->userdata);
+			break;
 		default: /*case HOOK_PRINT:*/
 			ret = ((hexchat_print_cb *)hook->callback) (word, hook->userdata);
 			break;
@@ -590,7 +600,7 @@ xit:
 	{
 		hook = list->data;
 		next = list->next;
-		if (hook->type == HOOK_DELETED)
+		if (!hook || hook->type == HOOK_DELETED)
 		{
 			hook_list = g_slist_remove (hook_list, hook);
 			free (hook);
@@ -606,15 +616,43 @@ xit:
 int
 plugin_emit_command (session *sess, char *name, char *word[], char *word_eol[])
 {
-	return plugin_hook_run (sess, name, word, word_eol, HOOK_COMMAND);
+	return plugin_hook_run (sess, name, word, word_eol, NULL, HOOK_COMMAND);
 }
 
-/* got a server PRIVMSG, NOTICE, numeric etc... */
+hexchat_event_attrs *
+hexchat_event_attrs_create (hexchat_plugin *ph)
+{
+	hexchat_event_attrs *attrs;
+
+	attrs = g_malloc (sizeof (*attrs));
 
+	attrs->server_time_utc = (time_t) 0;
+
+	return attrs;
+}
+
+void
+hexchat_event_attrs_free (hexchat_plugin *ph, hexchat_event_attrs *attrs)
+{
+	g_free (attrs);
+}
+
+/* got a server PRIVMSG, NOTICE, numeric etc... */
 int
 plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[])
 {
-	return plugin_hook_run (sess, name, word, word_eol, HOOK_SERVER);
+	return plugin_hook_run (sess, name, word, word_eol, NULL, HOOK_SERVER);
+}
+
+int
+plugin_emit_server_attrs (session *sess, char *name, char *word[], char *word_eol[],
+						  time_t server_time)
+{
+	hexchat_event_attrs attrs;
+
+	attrs.server_time_utc = server_time;
+
+	return plugin_hook_run (sess, name, word, word_eol, &attrs, HOOK_SERVER_ATTRS);
 }
 
 /* see if any plugins are interested in this print event */
@@ -622,7 +660,17 @@ plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[])
 int
 plugin_emit_print (session *sess, char *word[])
 {
-	return plugin_hook_run (sess, word[0], word, NULL, HOOK_PRINT);
+	return plugin_hook_run (sess, word[0], word, NULL, NULL, HOOK_PRINT);
+}
+
+int
+plugin_emit_print_attrs (session *sess, char *word[], time_t server_time)
+{
+	hexchat_event_attrs attrs;
+
+	attrs.server_time_utc = server_time;
+
+	return plugin_hook_run (sess, word[0], word, NULL, &attrs, HOOK_PRINT_ATTRS);
 }
 
 int
@@ -635,7 +683,7 @@ plugin_emit_dummy_print (session *sess, char *name)
 	for (i = 1; i < 32; i++)
 		word[i] = "\000";
 
-	return plugin_hook_run (sess, name, word, NULL, HOOK_PRINT);
+	return plugin_hook_run (sess, name, word, NULL, NULL, HOOK_PRINT);
 }
 
 int
@@ -663,7 +711,7 @@ plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval,
 	for (i = 5; i < PDIWORDS; i++)
 		word[i] = "\000";
 
-	return plugin_hook_run (sess, word[0], word, NULL, HOOK_PRINT);
+	return plugin_hook_run (sess, word[0], word, NULL, NULL, HOOK_PRINT);
 }
 
 static int
@@ -702,7 +750,7 @@ plugin_insert_hook (hexchat_hook *new_hook)
 	while (list)
 	{
 		hook = list->data;
-		if (hook->type == new_hook->type && hook->pri <= new_hook->pri)
+		if (hook && hook->type == new_hook->type && hook->pri <= new_hook->pri)
 		{
 			hook_list = g_slist_insert_before (hook_list, list, new_hook);
 			return;
@@ -780,7 +828,7 @@ plugin_command_list(GList *tmp_list)
 	while (list)
 	{
 		hook = list->data;
-		if (hook->type == HOOK_COMMAND)
+		if (hook && hook->type == HOOK_COMMAND)
 			tmp_list = g_list_prepend(tmp_list, hook->name);
 		list = list->next;
 	}
@@ -798,7 +846,7 @@ plugin_command_foreach (session *sess, void *userdata,
 	while (list)
 	{
 		hook = list->data;
-		if (hook->type == HOOK_COMMAND && hook->name[0])
+		if (hook && hook->type == HOOK_COMMAND && hook->name[0])
 		{
 			cb (sess, userdata, hook->name, hook->help_text);
 		}
@@ -869,6 +917,14 @@ hexchat_hook_server (hexchat_plugin *ph, const char *name, int pri,
 }
 
 hexchat_hook *
+hexchat_hook_server_attrs (hexchat_plugin *ph, const char *name, int pri,
+						   hexchat_serv_attrs_cb *callb, void *userdata)
+{
+	return plugin_add_hook (ph, HOOK_SERVER_ATTRS, pri, name, 0, callb, 0,
+							userdata);
+}
+
+hexchat_hook *
 hexchat_hook_print (hexchat_plugin *ph, const char *name, int pri,
 						hexchat_print_cb *callb, void *userdata)
 {
@@ -876,6 +932,14 @@ hexchat_hook_print (hexchat_plugin *ph, const char *name, int pri,
 }
 
 hexchat_hook *
+hexchat_hook_print_attrs (hexchat_plugin *ph, const char *name, int pri,
+						  hexchat_print_attrs_cb *callb, void *userdata)
+{
+	return plugin_add_hook (ph, HOOK_PRINT_ATTRS, pri, name, 0, callb, 0,
+							userdata);
+}
+
+hexchat_hook *
 hexchat_hook_timer (hexchat_plugin *ph, int timeout, hexchat_timer_cb *callb,
 					   void *userdata)
 {
@@ -1598,8 +1662,36 @@ hexchat_emit_print (hexchat_plugin *ph, const char *event_name, ...)
 			break;
 	}
 
-	i = text_emit_by_name ((char *)event_name, ph->context, argv[0], argv[1],
-								  argv[2], argv[3]);
+	i = text_emit_by_name ((char *)event_name, ph->context, (time_t) 0,
+						   argv[0], argv[1], argv[2], argv[3]);
+	va_end (args);
+
+	return i;
+}
+
+int
+hexchat_emit_print_attrs (hexchat_plugin *ph, hexchat_event_attrs *attrs,
+						  const char *event_name, ...)
+{
+	va_list args;
+	/* currently only 4 because no events use more than 4.
+		This can be easily expanded without breaking the API. */
+	char *argv[4] = {NULL, NULL, NULL, NULL};
+	int i = 0;
+
+	va_start (args, event_name);
+	while (1)
+	{
+		argv[i] = va_arg (args, char *);
+		if (!argv[i])
+			break;
+		i++;
+		if (i >= 4)
+			break;
+	}
+
+	i = text_emit_by_name ((char *)event_name, ph->context, attrs->server_time_utc,
+						   argv[0], argv[1], argv[2], argv[3]);
 	va_end (args);
 
 	return i;
diff --git a/src/common/plugin.h b/src/common/plugin.h
index dd878895..f75639e9 100644
--- a/src/common/plugin.h
+++ b/src/common/plugin.h
@@ -132,10 +132,24 @@ struct _hexchat_plugin
 		const char *var);
 	int (*hexchat_pluginpref_list) (hexchat_plugin *ph,
 		char *dest);
-	void *(*hexchat_dummy4) (hexchat_plugin *ph);
-	void *(*hexchat_dummy3) (hexchat_plugin *ph);
-	void *(*hexchat_dummy2) (hexchat_plugin *ph);
-	void *(*hexchat_dummy1) (hexchat_plugin *ph);
+	hexchat_hook *(*hexchat_hook_server_attrs) (hexchat_plugin *ph,
+		   const char *name,
+		   int pri,
+		   int (*callback) (char *word[], char *word_eol[],
+							hexchat_event_attrs *attrs, void *user_data),
+		   void *userdata);
+	hexchat_hook *(*hexchat_hook_print_attrs) (hexchat_plugin *ph,
+		  const char *name,
+		  int pri,
+		  int (*callback) (char *word[], hexchat_event_attrs *attrs,
+						   void *user_data),
+		  void *userdata);
+	int (*hexchat_emit_print_attrs) (hexchat_plugin *ph, hexchat_event_attrs *attrs,
+									 const char *event_name, ...);
+	hexchat_event_attrs *(*hexchat_event_attrs_create) (hexchat_plugin *ph);
+	void (*hexchat_event_attrs_free) (hexchat_plugin *ph,
+									  hexchat_event_attrs *attrs);
+
 	/* PRIVATE FIELDS! */
 	void *handle;		/* from dlopen */
 	char *filename;	/* loaded from */
@@ -156,7 +170,10 @@ void plugin_kill_all (void);
 void plugin_auto_load (session *sess);
 int plugin_emit_command (session *sess, char *name, char *word[], char *word_eol[]);
 int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[]);
+int plugin_emit_server_attrs (session *sess, char *name, char *word[],
+							  char *word_eol[], time_t server_time);
 int plugin_emit_print (session *sess, char *word[]);
+int plugin_emit_print_attrs (session *sess, char *word[], time_t server_time);
 int plugin_emit_dummy_print (session *sess, char *name);
 int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, int len, char *string);
 GList* plugin_command_list(GList *tmp_list);
diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c
index bea9f6f7..128c0c85 100644
--- a/src/common/proto-irc.c
+++ b/src/common/proto-irc.c
@@ -1493,6 +1493,9 @@ irc_inline (server *serv, char *buf, int len)
 
 	if (buf[0] == ':')
 	{
+		int eat1;
+		int eat2;
+
 		/* find a context for this message */
 		if (is_channel (serv, word[3]))
 		{
@@ -1506,15 +1509,29 @@ irc_inline (server *serv, char *buf, int len)
 
 		word[0] = type;
 		word_eol[1] = buf;	/* keep the ":" for plugins */
-		if (plugin_emit_server (sess, type, word, word_eol))
+
+		eat1 = plugin_emit_server (sess, type, word, word_eol);
+		eat2 = plugin_emit_server_attrs (sess, type, word, word_eol, 
+										 tags_data.timestamp);
+
+		if (eat1 || eat2)
 			goto xit;
+
 		word[1]++;
 		word_eol[1] = buf + 1;	/* but not for HexChat internally */
 
 	} else
 	{
+		int eat1;
+		int eat2;
+
 		word[0] = type = word[1];
-		if (plugin_emit_server (sess, type, word, word_eol))
+
+		eat1 = plugin_emit_server (sess, type, word, word_eol);
+		eat2 = plugin_emit_server_attrs (sess, type, word, word_eol,
+										 tags_data.timestamp);
+
+		if (eat1 || eat2)
 			goto xit;
 	}
 
diff --git a/src/common/servlist.c b/src/common/servlist.c
index 1e06acd4..51094687 100644
--- a/src/common/servlist.c
+++ b/src/common/servlist.c
@@ -207,7 +207,7 @@ static const struct defaultserver def[] =
 	{"EnterTheGame",	0},
 	{0,			"IRC.EnterTheGame.Com"},
 
-	{"EntropyNet",	0},
+	{"EntropyNet",	0, 0, 0, LOGIN_SASL},
 #ifdef USE_OPENSSL
 	{0,			"irc.entropynet.net/+6697"},
 #endif
@@ -251,7 +251,7 @@ static const struct defaultserver def[] =
 	{0,			"irc.ggn.net"},
 	{0,			"irc.vendetta.com"},
 
-	{"freenode", 0, "#hexchat", 0, LOGIN_SASL},
+	{"freenode", 0, 0, 0, LOGIN_SASL},
 #ifdef USE_OPENSSL
 	{0,				"chat.freenode.net/+6697"},
 #endif
@@ -510,7 +510,7 @@ static const struct defaultserver def[] =
 	{0,			"moo.slashnet.org"},
 	{0,			"radon.slashnet.org"},
 
-	{"Snoonet", 0},
+	{"Snoonet", 0, 0, 0, LOGIN_SASL},
 #ifdef USE_OPENSSL
 	{0,			"irc.snoonet.org/+6697"},
 #endif
@@ -550,6 +550,9 @@ static const struct defaultserver def[] =
 	{0,			"tahoma.starchat.net"},
 	{0,			"neo.starchat.net"},
 
+	{"StaticBox", 0, 0, 0, LOGIN_SASL},
+	{0,			"irc.staticbox.net"},
+
 	{"Station51", 0},
 #ifdef USE_OPENSSL
 	{0,			"irc.station51.net/+6697"},
diff --git a/src/common/text.c b/src/common/text.c
index a0e860ce..b825faba 100644
--- a/src/common/text.c
+++ b/src/common/text.c
@@ -2070,6 +2070,8 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
 	int i;
 	unsigned int stripcolor_args = (chanopt_is_set (prefs.hex_text_stripcolor_msg, sess->text_strip) ? 0xFFFFFFFF : 0);
 	char tbuf[NICKLEN + 4];
+	int eat1;
+	int eat2;
 
 	if (prefs.hex_text_color_nicks && (index == XP_TE_CHANACTION || index == XP_TE_CHANMSG))
 	{
@@ -2086,7 +2088,10 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
 	for (i = 5; i < PDIWORDS; i++)
 		word[i] = "\000";
 
-	if (plugin_emit_print (sess, word))
+	eat1 = plugin_emit_print (sess, word);
+	eat2 = plugin_emit_print_attrs (sess, word, timestamp);
+
+	if (eat1 || eat2)
 		return;
 
 	/* If a plugin's callback executes "/close", 'sess' may be invalid */
@@ -2158,14 +2163,15 @@ text_find_format_string (char *name)
 }
 
 int
-text_emit_by_name (char *name, session *sess, char *a, char *b, char *c, char *d)
+text_emit_by_name (char *name, session *sess, time_t timestamp,
+				   char *a, char *b, char *c, char *d)
 {
 	int i = 0;
 
 	i = pevent_find (name, &i);
 	if (i >= 0)
 	{
-		text_emit (i, sess, a, b, c, d, 0);
+		text_emit (i, sess, a, b, c, d, timestamp);
 		return 1;
 	}
 
diff --git a/src/common/text.h b/src/common/text.h
index 5a51c894..a9fd9d4e 100644
--- a/src/common/text.h
+++ b/src/common/text.h
@@ -55,7 +55,8 @@ void pevent_make_pntevts (void);
 int text_color_of (char *name);
 void text_emit (int index, session *sess, char *a, char *b, char *c, char *d,
 		time_t timestamp);
-int text_emit_by_name (char *name, session *sess, char *a, char *b, char *c, char *d);
+int text_emit_by_name (char *name, session *sess, time_t timestamp,
+					   char *a, char *b, char *c, char *d);
 char *text_validate (char **text, int *len);
 int get_stamp_str (char *fmt, time_t tim, char **ret);
 void format_event (session *sess, int index, char **args, char *o, int sizeofo, unsigned int stripcolor_args);
diff --git a/src/common/url.c b/src/common/url.c
index 10479127..1cdfdce7 100644
--- a/src/common/url.c
+++ b/src/common/url.c
@@ -32,15 +32,22 @@
 
 void *url_tree = NULL;
 GTree *url_btree = NULL;
-static int do_an_re (const char *word, int *start, int *end, int *type);
-static GRegex *re_url (void);
-static GRegex *re_host (void);
-static GRegex *re_host6 (void);
-static GRegex *re_email (void);
-static GRegex *re_nick (void);
-static GRegex *re_channel (void);
-static GRegex *re_path (void);
-
+static gboolean regex_match (const GRegex *re, const char *word,
+							 int *start, int *end);
+static const GRegex *re_url (void);
+static const GRegex *re_host (void);
+static const GRegex *re_host6 (void);
+static const GRegex *re_email (void);
+static const GRegex *re_nick (void);
+static const GRegex *re_channel (void);
+static const GRegex *re_path (void);
+static gboolean match_nick (const char *word, int *start, int *end);
+static gboolean match_channel (const char *word, int *start, int *end);
+static gboolean match_email (const char *word, int *start, int *end);
+static gboolean match_url (const char *word, int *start, int *end);
+static gboolean match_host (const char *word, int *start, int *end);
+static gboolean match_host6 (const char *word, int *start, int *end);
+static gboolean match_path (const char *word, int *start, int *end);
 
 static int
 url_free (char *url, void *data)
@@ -189,50 +196,111 @@ static int laststart = 0;
 static int lastend = 0;
 static int lasttype = 0;
 
-static int
-strchrs (char c, char *s)
-{
-	while (*s)
-		if (c == *s++)
-			return TRUE;
-	return FALSE;
-}
+#define NICKPRE "~+!@%&"
+#define CHANPRE "#&!+"
 
-#define NICKPRE "~+!@%%&"
 int
 url_check_word (const char *word)
 {
+	struct {
+		gboolean (*match) (const char *word, int *start, int *end);
+		int type;
+	} m[] = {
+	   { match_url,     WORD_URL },
+	   { match_email,   WORD_EMAIL },
+	   { match_nick,    WORD_NICK },
+	   { match_channel, WORD_CHANNEL },
+	   { match_host6,   WORD_HOST6 },
+	   { match_host,    WORD_HOST },
+	   { match_path,    WORD_PATH },
+	   { NULL,          0}
+	};
+	int i;
+
 	laststart = lastend = lasttype = 0;
-	if (do_an_re (word, &laststart, &lastend, &lasttype))
-	{
-		switch (lasttype)
+
+	for (i = 0; m[i].match; i++)
+		if (m[i].match (word, &laststart, &lastend))
 		{
-			char *str;
-
-			case WORD_NICK:
-				if (strchrs (word[laststart], NICKPRE))
-					laststart++;
-				str = g_strndup (&word[laststart], lastend - laststart);
-				if (!userlist_find (current_sess, str))
-					lasttype = 0;
-				g_free (str);
-				return lasttype;
-			case WORD_EMAIL:
-				if (!isalnum (word[laststart]))
-					laststart++;
-				/* Fall through */
-			case WORD_URL:
-			case WORD_HOST:
-			case WORD_HOST6:
-			case WORD_CHANNEL:
-			case WORD_PATH:
-				return lasttype;
-			default:
-				return 0;	/* Should not occur */
+			lasttype = m[i].type;
+			return lasttype;
 		}
+
+	return 0;
+}
+
+static gboolean
+match_nick (const char *word, int *start, int *end)
+{
+	const server *serv = current_sess->server;
+	const char *nick_prefixes = serv ? serv->nick_prefixes : NICKPRE;
+	char *str;
+
+	if (!regex_match (re_nick (), word, start, end))
+		return FALSE;
+
+	/* ignore matches with prefixes that the server doesn't use */
+	if (strchr (NICKPRE, word[*start])
+		&& !strchr (nick_prefixes, word[*start]))
+		return FALSE;
+	
+	/* nick prefix is not part of the matched word */
+	if (strchr (nick_prefixes, word[*start]))
+		(*start)++;
+
+	str = g_strndup (&word[*start], *end - *start);
+
+	if (!userlist_find (current_sess, str))
+	{
+		g_free (str);
+		return FALSE;
 	}
-	else
-		return 0;
+
+	g_free (str);
+
+	return TRUE;
+}
+
+static gboolean
+match_channel (const char *word, int *start, int *end)
+{
+	const server *serv = current_sess->server;
+	const char *chan_prefixes = serv ? serv->chantypes : CHANPRE;
+
+	if (!regex_match (re_channel (), word, start, end))
+		return FALSE;
+
+	return strchr (chan_prefixes, word[*start]) != NULL;
+}
+
+static gboolean
+match_email (const char *word, int *start, int *end)
+{
+	return regex_match (re_email (), word, start, end);
+}
+
+static gboolean
+match_url (const char *word, int *start, int *end)
+{
+	return regex_match (re_url (), word, start, end);
+}
+
+static gboolean
+match_host (const char *word, int *start, int *end)
+{
+	return regex_match (re_host (), word, start, end);
+}
+
+static gboolean
+match_host6 (const char *word, int *start, int *end)
+{
+	return regex_match (re_host6 (), word, start, end);
+}
+
+static gboolean
+match_path (const char *word, int *start, int *end)
+{
+	return regex_match (re_path (), word, start, end);
 }
 
 /* List of IRC commands for which contents (and thus possible URLs)
@@ -307,51 +375,33 @@ url_last (int *lstart, int *lend)
 	return lasttype;
 }
 
-static int
-do_an_re(const char *word, int *start, int *end, int *type)
+static gboolean
+regex_match (const GRegex *re, const char *word, int *start, int *end)
 {
-	typedef struct func_s {
-		GRegex *(*fn)(void);
-		int type;
-	} func_t;
-	func_t funcs[] =
-	{
-		{ re_url, WORD_URL },
-		{ re_email, WORD_EMAIL },
-		{ re_channel, WORD_CHANNEL },
-		{ re_host6, WORD_HOST6 },
-		{ re_host, WORD_HOST },
-		{ re_path, WORD_PATH },
-		{ re_nick, WORD_NICK }
-	};
-
 	GMatchInfo *gmi;
-	int k;
 
-	for (k = 0; k < sizeof funcs / sizeof (func_t); k++)
+	g_regex_match (re, word, 0, &gmi);
+	
+	if (!g_match_info_matches (gmi))
 	{
-		g_regex_match (funcs[k].fn(), word, 0, &gmi);
-		if (!g_match_info_matches (gmi))
-		{
-			g_match_info_free (gmi);
-			continue;
-		}
-		while (g_match_info_matches (gmi))
-		{
-			g_match_info_fetch_pos (gmi, 0, start, end);
-			g_match_info_next (gmi, NULL);
-		}
 		g_match_info_free (gmi);
-		*type = funcs[k].type;
-		return TRUE;
+		return FALSE;
 	}
-
-	return FALSE;
+	
+	while (g_match_info_matches (gmi))
+	{
+		g_match_info_fetch_pos (gmi, 0, start, end);
+		g_match_info_next (gmi, NULL);
+	}
+	
+	g_match_info_free (gmi);
+	
+	return TRUE;
 }
 
 /*	Miscellaneous description --- */
-#define DOMAIN "[a-z0-9][-a-z0-9]*(\\.[-a-z0-9]+)*\\."
-#define TLD "[a-z][-a-z0-9]*[a-z]"
+#define DOMAIN "[a-z0-9][-a-z0-9]*(\\.[-a-z0-9]+)*"
+#define TLD "\\.[a-z][-a-z0-9]*[a-z]"
 #define IPADDR "[0-9]{1,3}(\\.[0-9]{1,3}){3}"
 #define IPV6GROUP "([0-9a-f]{0,4})"
 #define IPV6ADDR "((" IPV6GROUP "(:" IPV6GROUP "){7})"	\
@@ -359,6 +409,7 @@ do_an_re(const char *word, int *start, int *end, int *type)
 #define HOST "(" DOMAIN TLD "|" IPADDR "|" IPV6ADDR ")"
 /* In urls the IPv6 must be enclosed in square brackets */
 #define HOST_URL "(" DOMAIN TLD "|" IPADDR "|" "\\[" IPV6ADDR "\\]" ")"
+#define HOST_URL_OPT_TLD "(" DOMAIN "|" HOST_URL ")"
 #define PORT "(:[1-9][0-9]{0,4})"
 #define OPT_PORT "(" PORT ")?"
 
@@ -375,7 +426,7 @@ make_re (char *grist)
 
 /*	HOST description --- */
 /* (see miscellaneous above) */
-static GRegex *
+static const GRegex *
 re_host (void)
 {
 	static GRegex *host_ret;
@@ -383,7 +434,7 @@ re_host (void)
 
 	if (host_ret) return host_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			"(" HOST_URL PORT ")|(" HOST ")"
 		")"
@@ -392,7 +443,7 @@ re_host (void)
 	return host_ret;
 }
 
-static GRegex *
+static const GRegex *
 re_host6 (void)
 {
 	static GRegex *host6_ret;
@@ -400,7 +451,7 @@ re_host6 (void)
 
 	if (host6_ret) return host6_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			"(" IPV6ADDR ")|(" "\\[" IPV6ADDR "\\]" PORT ")"
 		")"
@@ -488,7 +539,7 @@ struct
 	{ NULL,        "",  0}
 };
 
-static GRegex *
+static const GRegex *
 re_url (void)
 {
 	static GRegex *url_ret = NULL;
@@ -517,7 +568,7 @@ re_url (void)
 			g_string_append (grist_gstr, USERINFO "?");
 
 		if (uri[i].flags & URI_AUTHORITY)
-			g_string_append (grist_gstr, HOST_URL OPT_PORT);
+			g_string_append (grist_gstr, HOST_URL_OPT_TLD OPT_PORT);
 		
 		if (uri[i].flags & URI_PATH)
 		{
@@ -545,7 +596,7 @@ re_url (void)
 /*	EMAIL description --- */
 #define EMAIL "[a-z][-_a-z0-9]+@" "(" HOST_URL ")"
 
-static GRegex *
+static const GRegex *
 re_email (void)
 {
 	static GRegex *email_ret;
@@ -553,7 +604,7 @@ re_email (void)
 
 	if (email_ret) return email_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			EMAIL
 		")"
@@ -581,7 +632,7 @@ re_email (void)
 #define NICK1 "[" NICKHYP NICKLET NICKDIG NICKSPE "]*"
 #define NICK	NICK0 NICK1
 
-static GRegex *
+static const GRegex *
 re_nick (void)
 {
 	static GRegex *nick_ret;
@@ -589,7 +640,7 @@ re_nick (void)
 
 	if (nick_ret) return nick_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			NICK
 		")"
@@ -599,9 +650,9 @@ re_nick (void)
 }
 
 /*	CHANNEL description --- */
-#define CHANNEL "#[^ \t\a,:]+"
+#define CHANNEL "[" CHANPRE "][^ \t\a,:]+"
 
-static GRegex *
+static const GRegex *
 re_channel (void)
 {
 	static GRegex *channel_ret;
@@ -609,7 +660,7 @@ re_channel (void)
 
 	if (channel_ret) return channel_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			CHANNEL
 		")"
@@ -627,7 +678,7 @@ re_channel (void)
 #define FS_PATH "^(/|\\./|\\.\\./).*"
 #endif
 
-static GRegex *
+static const GRegex *
 re_path (void)
 {
 	static GRegex *path_ret;
@@ -635,7 +686,7 @@ re_path (void)
 
 	if (path_ret) return path_ret;
 
-	grist = g_strdup_printf (
+	grist = g_strdup (
 		"("
 			FS_PATH
 		")"
diff --git a/src/fe-gtk/dccgui.c b/src/fe-gtk/dccgui.c
index 24d3bcbf..a3c2619a 100644
--- a/src/fe-gtk/dccgui.c
+++ b/src/fe-gtk/dccgui.c
@@ -78,6 +78,7 @@ struct dccwindow
 	GtkWidget *accept_button;
 	GtkWidget *resume_button;
 	GtkWidget *open_button;
+	GtkWidget *clear_button; /* clears aborted and completed requests */	
 
 	GtkWidget *file_label;
 	GtkWidget *address_label;
@@ -380,6 +381,50 @@ dcc_append (struct DCC *dcc, GtkListStore *store, gboolean prepend)
 		dcc_prepare_row_send (dcc, store, &iter, FALSE);
 }
 
+/* Returns aborted and completed transfers. */
+static GSList *
+dcc_get_completed (void)
+{
+	struct DCC *dcc;
+	GtkTreeIter iter;
+	GtkTreeModel *model;	
+	GSList *completed = NULL;
+
+	model = GTK_TREE_MODEL (dccfwin.store);
+	if (gtk_tree_model_get_iter_first (model, &iter))
+	{
+		do
+		{
+			gtk_tree_model_get (model, &iter, COL_DCC, &dcc, -1);
+			if (is_dcc_completed (dcc))
+				completed = g_slist_prepend (completed, dcc);
+				
+		} while (gtk_tree_model_iter_next (model, &iter));
+	}
+
+	return completed;
+}
+
+static gboolean
+dcc_completed_transfer_exists (void)
+{
+	gboolean exist;
+	GSList *comp_list;
+	
+	comp_list = dcc_get_completed (); 
+	exist = comp_list != NULL;
+	
+	g_slist_free (comp_list);	
+	return exist;
+}
+
+static void
+update_clear_button_sensitivity (void)
+{
+	gboolean sensitive = dcc_completed_transfer_exists ();
+	gtk_widget_set_sensitive (dccfwin.clear_button, sensitive);
+}
+
 static void
 dcc_fill_window (int flags)
 {
@@ -426,6 +471,8 @@ dcc_fill_window (int flags)
 		gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dccfwin.store), &iter);
 		gtk_tree_selection_select_iter (dccfwin.sel, &iter);
 	}
+	
+	update_clear_button_sensitivity ();
 }
 
 /* return list of selected DCCs */
@@ -511,6 +558,9 @@ abort_clicked (GtkWidget * wid, gpointer none)
 		dcc_abort (dcc->serv->front_session, dcc);
 	}
 	g_slist_free (start);
+	
+	/* Enable the clear button if it wasn't already enabled */
+	update_clear_button_sensitivity ();
 }
 
 static void
@@ -530,6 +580,27 @@ accept_clicked (GtkWidget * wid, gpointer none)
 }
 
 static void
+clear_completed (GtkWidget * wid, gpointer none)
+{
+	struct DCC *dcc;
+	GSList *completed;
+
+	/* Make a new list of only the completed items and abort each item.
+	 * A new list is made because calling dcc_abort removes items from the original list,
+	 * making it impossible to iterate over that list directly.
+	*/
+	for (completed = dcc_get_completed (); completed; completed = completed->next)
+	{
+		dcc = completed->data;
+		dcc_abort (dcc->serv->front_session, dcc);
+	}
+
+	/* The data was freed by dcc_close */
+	g_slist_free (completed);
+	update_clear_button_sensitivity ();
+}
+
+static void
 browse_folder (char *dir)
 {
 #ifdef WIN32
@@ -812,6 +883,7 @@ fe_dcc_open_recv_win (int passive)
 	dccfwin.abort_button = gtkutil_button (bbox, GTK_STOCK_CANCEL, 0, abort_clicked, 0, _("Abort"));
 	dccfwin.accept_button = gtkutil_button (bbox, GTK_STOCK_APPLY, 0, accept_clicked, 0, _("Accept"));
 	dccfwin.resume_button = gtkutil_button (bbox, GTK_STOCK_REFRESH, 0, resume_clicked, 0, _("Resume"));
+	dccfwin.clear_button = gtkutil_button (bbox, GTK_STOCK_CLEAR, 0, clear_completed, 0, _("Clear"));
 	dccfwin.open_button = gtkutil_button (bbox, 0, 0, browse_dcc_folder, 0, _("Open Folder..."));
 	gtk_widget_set_sensitive (dccfwin.accept_button, FALSE);
 	gtk_widget_set_sensitive (dccfwin.resume_button, FALSE);
@@ -1055,6 +1127,8 @@ fe_dcc_update (struct DCC *dcc)
 	default:
 		dcc_update_chat (dcc);
 	}
+
+	update_clear_button_sensitivity ();
 }
 
 void
diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c
index c8a80369..acba80a5 100644
--- a/src/fe-gtk/fe-gtk.c
+++ b/src/fe-gtk/fe-gtk.c
@@ -220,26 +220,26 @@ fe_args (int argc, char *argv[])
 
 	if (arg_show_version)
 	{
+		buffer = g_strdup_printf ("%s %s", PACKAGE_NAME, PACKAGE_VERSION);
 #ifdef WIN32
-		buffer = g_strdup_printf (DISPLAY_NAME " " PACKAGE_VERSION "\n");
 		gtk_init (&argc, &argv);
 		create_msg_dialog ("Version Information", buffer);
-		g_free (buffer);
 #else
-		 printf (PACKAGE_NAME" "PACKAGE_VERSION"\n");
+		puts (buffer);
 #endif
+		g_free (buffer);
 
 		return 0;
 	}
 
 	if (arg_show_autoload)
 	{
-		buffer = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "addons\n", get_xdir ());
+		buffer = g_strdup_printf ("%s%caddons%c", get_xdir(), G_DIR_SEPARATOR, G_DIR_SEPARATOR);
 #ifdef WIN32
 		gtk_init (&argc, &argv);
 		create_msg_dialog ("Plugin/Script Auto-load Directory", buffer);
 #else
-		printf (buffer);
+		puts (buffer);
 #endif
 		g_free (buffer);
 
@@ -248,12 +248,12 @@ fe_args (int argc, char *argv[])
 
 	if (arg_show_config)
 	{
-		buffer = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "\n", get_xdir ());
+		buffer = g_strdup_printf ("%s%c", get_xdir(), G_DIR_SEPARATOR);
 #ifdef WIN32
 		gtk_init (&argc, &argv);
 		create_msg_dialog ("User Config Directory", buffer);
 #else
-		printf (buffer);
+		puts (buffer);
 #endif
 		g_free (buffer);
 
diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj
index 0c149928..f8c6377a 100644
--- a/src/fe-gtk/fe-gtk.vcxproj
+++ b/src/fe-gtk/fe-gtk.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

@@ -81,7 +80,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/src/fe-gtk/fkeys.c b/src/fe-gtk/fkeys.c
index 8a9a13c2..ba9599e1 100644
--- a/src/fe-gtk/fkeys.c
+++ b/src/fe-gtk/fkeys.c
@@ -148,7 +148,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
 	{key_action_insert, "Insert in Buffer",
 	 N_("The \002Insert in Buffer\002 command will insert the contents of Data 1 into the entry where the key sequence was pressed at the current cursor position")},
 	{key_action_scroll_page, "Scroll Page",
-	 N_("The \002Scroll Page\002 command scrolls the text widget up or down one page or one line. Set Data 1 to either Up, Down, +1 or -1.")},
+	 N_("The \002Scroll Page\002 command scrolls the text widget up or down one page or one line. Set Data 1 to either Top, Bottom, Up, Down, +1 or -1.")},
 	{key_action_set_buffer, "Set Buffer",
 	 N_("The \002Set Buffer\002 command sets the entry where the key sequence was entered to the contents of Data 1")},
 	{key_action_history_up, "Last Command",
@@ -395,6 +395,8 @@ key_load_defaults ()
 		"S\nNext\nChange Selected Nick\nD1!\nD2!\n\n"\
 		"S\nPrior\nChange Selected Nick\nD1:Up\nD2!\n\n"\
 		"None\nNext\nScroll Page\nD1:Down\nD2!\n\n"\
+		"C\nHome\nScroll Page\nD1:Top\nD2!\n\n"\
+		"C\nEnd\nScroll Page\nD1:Bottom\nD2!\n\n"\
 		"None\nPrior\nScroll Page\nD1:Up\nD2!\n\n"\
 		"S\nDown\nScroll Page\nD1:+1\nD2!\n\n"\
 		"S\nUp\nScroll Page\nD1:-1\nD2!\n\n"\
@@ -1279,13 +1281,19 @@ key_action_scroll_page (GtkWidget * wid, GdkEventKey * evt, char *d1,
 {
 	int value, end;
 	GtkAdjustment *adj;
-	enum scroll_type { PAGE_UP, PAGE_DOWN, LINE_UP, LINE_DOWN };
+	enum scroll_type { PAGE_TOP, PAGE_BOTTOM, PAGE_UP, PAGE_DOWN, LINE_UP, LINE_DOWN };
 	int type = PAGE_DOWN;
 
 	if (d1)
 	{
-		if (!g_ascii_strcasecmp (d1, "up"))
+		if (!g_ascii_strcasecmp (d1, "top"))
+			type = PAGE_TOP;
+		else if (!g_ascii_strcasecmp (d1, "bottom"))
+			type = PAGE_BOTTOM;
+		else if (!g_ascii_strcasecmp (d1, "up"))
 			type = PAGE_UP;
+		else if (!g_ascii_strcasecmp (d1, "down"))
+			type = PAGE_DOWN;
 		else if (!g_ascii_strcasecmp (d1, "+1"))
 			type = LINE_DOWN;
 		else if (!g_ascii_strcasecmp (d1, "-1"))
@@ -1300,21 +1308,29 @@ key_action_scroll_page (GtkWidget * wid, GdkEventKey * evt, char *d1,
 
 	switch (type)
 	{
-	case LINE_UP:
-		value = adj->value - 1.0;
+	case PAGE_TOP:
+		value = 0;
 		break;
 
-	case LINE_DOWN:
-		value = adj->value + 1.0;
+	case PAGE_BOTTOM:
+		value = end;
 		break;
 
 	case PAGE_UP:
 		value = adj->value - (adj->page_size - 1);
 		break;
 
-	default:	/* PAGE_DOWN */
+	case PAGE_DOWN:
 		value = adj->value + (adj->page_size - 1);
 		break;
+
+	case LINE_UP:
+		value = adj->value - 1.0;
+		break;
+
+	case LINE_DOWN:
+		value = adj->value + 1.0;
+		break;
 	}
 
 	if (value < 0)
diff --git a/src/fe-gtk/joind.c b/src/fe-gtk/joind.c
index b58d662a..55d62e3b 100644
--- a/src/fe-gtk/joind.c
+++ b/src/fe-gtk/joind.c
@@ -34,6 +34,7 @@
 #include "../common/hexchat.h"
 #include "../common/hexchatc.h"
 #include "../common/server.h"
+#include "../common/servlist.h"
 #include "../common/fe.h"
 #include "fe-gtk.h"
 #include "chanlist.h"
@@ -241,6 +242,13 @@ joind_show_dialog (server *serv)
 							G_CALLBACK (joind_radio2_cb), serv);
 	g_signal_connect (G_OBJECT (okbutton1), "clicked",
 							G_CALLBACK (joind_ok_cb), serv);
+							
+	if (serv->network)
+		if (g_ascii_strcasecmp(((ircnet*)serv->network)->name, "freenode") == 0)
+		{
+			gtk_entry_set_text (GTK_ENTRY (entry1), "#hexchat");
+			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(radiobutton2), TRUE);
+		}
 
 	gtk_widget_grab_focus (okbutton1);
 	gtk_widget_show_all (dialog1);
diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c
index 1948348a..58c28e51 100644
--- a/src/fe-gtk/menu.c
+++ b/src/fe-gtk/menu.c
@@ -1545,7 +1545,7 @@ menu_ctcpguiopen (void)
 static void
 menu_docs (GtkWidget *wid, gpointer none)
 {
-	fe_open_url ("http://docs.hexchat.org/");
+	fe_open_url ("http://hexchat.readthedocs.org");
 }
 
 /*static void
diff --git a/src/fe-text/fe-text.vcxproj b/src/fe-text/fe-text.vcxproj
index 1c42c967..2a7c3742 100644
--- a/src/fe-text/fe-text.vcxproj
+++ b/src/fe-text/fe-text.vcxproj
@@ -59,7 +59,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

@@ -79,7 +78,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/src/pixmaps/pixmaps.vcxproj b/src/pixmaps/pixmaps.vcxproj
index dbb18520..a86a7e13 100644
--- a/src/pixmaps/pixmaps.vcxproj
+++ b/src/pixmaps/pixmaps.vcxproj
@@ -57,7 +57,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -76,7 +75,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/src/version-script b/src/version-script
index a98651db..a7ed1495 100644
--- a/src/version-script
+++ b/src/version-script
@@ -1,8 +1,12 @@
 EXPORTED {
 	global:
 		hexchat_hook_command;
+		hexchat_event_attrs_create;
+		hexchat_event_attrs_free;
 		hexchat_hook_server;
+		hexchat_hook_server_attrs;
 		hexchat_hook_print;
+		hexchat_hook_print_attrs;
 		hexchat_hook_timer;
 		hexchat_hook_fd;
 		hexchat_unhook;
@@ -25,6 +29,7 @@ EXPORTED {
 		hexchat_plugingui_add;
 		hexchat_plugingui_remove;
 		hexchat_emit_print;
+		hexchat_emit_print_attrs;
 		hexchat_list_time;
 		hexchat_gettext;
 		hexchat_send_modes;
diff --git a/src/version/version.vcxproj b/src/version/version.vcxproj
index ca429b08..f1520f73 100644
--- a/src/version/version.vcxproj
+++ b/src/version/version.vcxproj
@@ -57,7 +57,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

@@ -77,7 +76,6 @@
     <ClCompile>

       <PrecompiledHeader>

       </PrecompiledHeader>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

       <PreprocessorDefinitions>WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj
index 3146e6be..1586d200 100644
--- a/win32/copy/copy.vcxproj
+++ b/win32/copy/copy.vcxproj
@@ -52,7 +52,6 @@
   </PropertyGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>

@@ -67,7 +66,6 @@
   </ItemDefinitionGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>

diff --git a/win32/hexchat.props b/win32/hexchat.props
index 453240d8..25fdb14a 100644
--- a/win32/hexchat.props
+++ b/win32/hexchat.props
@@ -100,6 +100,11 @@ xcopy /q /s /i "$(DepsRoot)\share\locale" "$(HexChatRel)\share\locale"
 		<ClCompile>

 			<WarningLevel>Level3</WarningLevel>

 			<DisableSpecificWarnings>4996</DisableSpecificWarnings>

+			<!-- UNCOMMENT ONLY ONE -->

+			<!--Optimization>Disabled</Optimization-->

+			<Optimization>MaxSpeed</Optimization>

+			<!--Optimization>MinSpace</Optimization-->

+			<!--Optimization>Full</Optimization-->

 		</ClCompile>

 	</ItemDefinitionGroup>

 

diff --git a/win32/installer/installer.vcxproj b/win32/installer/installer.vcxproj
index faa13c06..87142c2c 100644
--- a/win32/installer/installer.vcxproj
+++ b/win32/installer/installer.vcxproj
@@ -52,7 +52,6 @@
   </PropertyGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>

@@ -76,7 +75,6 @@ type hexchat-x86.skel.iss &gt;&gt; "$(OutDir)\hexchat-x86.iss"
   </ItemDefinitionGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>

diff --git a/win32/nls/nls.vcxproj b/win32/nls/nls.vcxproj
index c1da078a..35ca3e9d 100644
--- a/win32/nls/nls.vcxproj
+++ b/win32/nls/nls.vcxproj
@@ -52,7 +52,6 @@
   </PropertyGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>

@@ -73,7 +72,6 @@ mkdir "$(OutDir)\locale\%%~nA\LC_MESSAGES"
   </ItemDefinitionGroup>

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

     <ClCompile>

-      <Optimization>MaxSpeed</Optimization>

       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

     </ClCompile>