summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTingPing <tingping@tingping.se>2013-05-02 11:20:05 -0400
committerTingPing <tingping@tingping.se>2013-05-03 20:26:58 -0400
commitffa1ea735875442501e4f742cc3090903c5da001 (patch)
tree65b66ed2013ecde5d61e2f44ff83111a76a0029a
parentc4384265e41772d8e7709732c76cfb868821028c (diff)
Add python3 plugin
-rw-r--r--configure.ac10
-rw-r--r--plugins/python/python.c424
-rw-r--r--plugins/python/python2.vcxproj (renamed from plugins/python/python.vcxproj)16
-rw-r--r--plugins/python/python2.vcxproj.filters (renamed from plugins/python/python.vcxproj.filters)0
-rw-r--r--plugins/python/python3.vcxproj109
-rw-r--r--plugins/python/python3.vcxproj.filters21
-rw-r--r--src/common/plugin.c3
-rw-r--r--win32/hexchat.props15
-rw-r--r--win32/hexchat.sln11
-rw-r--r--win32/installer/hexchat-x64.skel.iss13
-rw-r--r--win32/installer/hexchat-x86.skel.iss13
11 files changed, 441 insertions, 194 deletions
diff --git a/configure.ac b/configure.ac
index fac9ee8a..98cea144 100644
--- a/configure.ac
+++ b/configure.ac
@@ -352,13 +352,17 @@ if test "x$python" != xno ; then
                 PYPLAT_INC=`$pythonpath -c 'import distutils.sysconfig; print(distutils.sysconfig.get_python_inc(plat_specific=True));'`
                 changequote([, ])dnl
                 AC_MSG_RESULT($PY_VER)
-                $pythonpath -c "import sys; float(sys.version[[:3]]) >= 2.2 and int(sys.version[[0]]) < 3 or sys.exit(1)"
+                $pythonpath -c "import sys; float(sys.version[[:3]]) >= 2.6 and int(sys.version[[0]]) <= 3 or sys.exit(1)"
                 if test "$?" != "1"; then
                         AC_MSG_CHECKING(Python compile flags)
                         PY_PREFIX=`$pythonpath -c 'import sys; print(sys.prefix)'`
                         PY_EXEC_PREFIX=`$pythonpath -c 'import sys; print(sys.exec_prefix)'`
                         if test -f $PY_INC/Python.h || test -f $PYPLAT_INC/Python.h; then
-                                PY_LIBS="-L$PY_LIB/config -lpython$PY_VER -lpthread -lutil"
+								AS_VERSION_COMPARE($PY_VER, 3.0,
+									[PYL="$PY_VER"], # less than
+									[PYL="${PY_VER}m"], # equal
+									[PYL="${PY_VER}m"]) # greater than
+                                PY_LIBS="-L$PY_LIB/config -lpython$PYL -lpthread -lutil"
                                 PY_CFLAGS="-I$PY_INC -I$PYPLAT_INC"
                                 AC_MSG_RESULT(ok)
                         else
@@ -366,7 +370,7 @@ if test "x$python" != xno ; then
                                 AC_MSG_RESULT([Can\'t find Python.h])
                         fi
                 else
-                        echo "Python is too old or too new. Only 2.2-2.7 are supported."
+                        echo "Python is too old or too new. Only 2.6-3.x are supported."
                         python=no
                 fi
         fi
diff --git a/plugins/python/python.c b/plugins/python/python.c
index 7c2e5a95..707da20a 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -58,6 +58,7 @@
 
 #ifdef WIN32
 #include <direct.h>
+#include <glib/gstdio.h>
 #include "../../src/dirent/dirent-win32.h"
 #include "../../config-win32.h"
 #else
@@ -71,14 +72,36 @@
 #include "structmember.h"
 #include "pythread.h"
 
-#define VERSION_MAJOR 0
-#define VERSION_MINOR 9
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 0
 
+#if PY_MAJOR_VERSION == 2
 #ifdef WIN32
-#undef WITH_THREAD /* Thread support locks up xchat on Win32. */
-#define VERSION "0.9/2.7"	/* Linked to python27.dll */
+#undef WITH_THREAD
+#define VERSION "1.0/2.7"	/* Linked to python27.dll */
+#endif
+
+#undef PyLong_Check
+#define PyLong_Check PyInt_Check
+#define PyLong_AsLong PyInt_AsLong
+#define PyLong_FromLong PyInt_FromLong
+
+#undef PyUnicode_Check
+#undef PyUnicode_FromString
+#define PyUnicode_Check PyString_Check
+#define PyUnicode_AsFormat PyString_AsFormat
+#define PyUnicode_FromString PyString_FromString
+#define PyUnicode_AsUTF8 PyString_AsString
+
 #else
-#define VERSION "0.9"
+#define IS_PY3K
+#ifdef WIN32
+#define VERSION "1.0/3.3"	/* Linked to python33.dll */
+#endif
+#endif
+
+#ifndef VERSION
+#define VERSION "1.0"
 #endif
 
 #define NONE 0
@@ -252,8 +275,7 @@ static PyObject *Context_compare(ContextObject *a, ContextObject *b, int op);
 static PyObject *Context_FromContext(hexchat_context *context);
 static PyObject *Context_FromServerAndChannel(char *server, char *channel);
 
-static PyObject *Plugin_New(char *filename, PyMethodDef *xchat_methods,
-			    PyObject *xcoobj);
+static PyObject *Plugin_New(char *filename, PyObject *xcoobj);
 static PyObject *Plugin_GetCurrent();
 static PluginObject *Plugin_ByString(char *str);
 static Hook *Plugin_AddHook(int type, PyObject *plugin, PyObject *callback,
@@ -299,10 +321,10 @@ static int Command_Py(char *word[], char *word_eol[], void *userdata);
 /* ===================================================================== */
 /* Static declarations and definitions */
 
-staticforward PyTypeObject Plugin_Type;
-staticforward PyTypeObject XChatOut_Type;
-staticforward PyTypeObject Context_Type;
-staticforward PyTypeObject ListItem_Type;
+static PyTypeObject Plugin_Type;
+static PyTypeObject XChatOut_Type;
+static PyTypeObject Context_Type;
+static PyTypeObject ListItem_Type;
 
 static PyThreadState *main_tstate = NULL;
 static void *thread_timer = NULL;
@@ -355,7 +377,7 @@ Util_BuildList(char *word[])
 		return NULL;
 	}
 	for (i = 0; i != listsize; i++) {
-		PyObject *o = PyString_FromString(word[i]);
+		PyObject *o = PyUnicode_FromString(word[i]);
 		if (o == NULL) {
 			Py_DECREF(list);
 			PyErr_Print();
@@ -400,25 +422,10 @@ Util_Autoload()
 
 	xdir = hexchat_get_info(ph, "configdir");
 
-	/* don't pollute the filesystem with script files, this only causes misuse of the folders
-	 * only use ~/.config/hexchat/addons/ and %APPDATA%\HexChat\addons */
-#if 0
-	/* auto-load from ~/.config/hexchat/ or %APPDATA%\HexChat\ */
-	Util_Autoload_from(hexchat_get_info(ph, "configdir"));
-#endif
-
 	/* auto-load from subdirectory addons */
-	sub_dir = malloc (strlen (xdir) + 8);
-	strcpy (sub_dir, xdir);
-	strcat (sub_dir, "/addons");
+	sub_dir = g_build_filename (xdir, "addons", NULL);
 	Util_Autoload_from(sub_dir);
-	free (sub_dir);
-
-#if 0
-#ifdef WIN32	/* also auto-load C:\Program Files\HexChat\Plugins\*.py */
-	Util_Autoload_from(HEXCHATLIBDIR"/plugins");
-#endif
-#endif
+	g_free (sub_dir);
 }
 
 static char *
@@ -511,7 +518,7 @@ Callback_Command(char *word[], char *word_eol[], void *userdata)
 		ret = HEXCHAT_EAT_NONE;
 		Py_DECREF(retobj);
 	} else if (retobj) {
-		ret = PyInt_AsLong(retobj);
+		ret = PyLong_AsLong(retobj);
 		Py_DECREF(retobj);
 	} else {
 		PyErr_Print();
@@ -597,7 +604,7 @@ Callback_Print(char *word[], void *userdata)
 		ret = HEXCHAT_EAT_NONE;
 		Py_DECREF(retobj);
 	} else if (retobj) {
-		ret = PyInt_AsLong(retobj);
+		ret = PyLong_AsLong(retobj);
 		Py_DECREF(retobj);
 	} else {
 		PyErr_Print();
@@ -643,7 +650,9 @@ static int
 Callback_ThreadTimer(void *userdata)
 {
 	RELEASE_XCHAT_LOCK();
+#ifndef WIN32
 	usleep(1);
+#endif
 	ACQUIRE_XCHAT_LOCK();
 	return 1;
 }
@@ -672,7 +681,7 @@ XChatOut_New()
 static void
 XChatOut_dealloc(PyObject *self)
 {
-	self->ob_type->tp_free((PyObject *)self);
+	Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
 /* This is a little bit complex because we have to buffer data
@@ -765,9 +774,8 @@ static PyMethodDef XChatOut_methods[] = {
 	{NULL, NULL}
 };
 
-statichere PyTypeObject XChatOut_Type = {
-	PyObject_HEAD_INIT(NULL)
-	0,			/*ob_size*/
+static PyTypeObject XChatOut_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
 	"hexchat.XChatOut",	/*tp_name*/
 	sizeof(XChatOutObject),	/*tp_basicsize*/
 	0,			/*tp_itemsize*/
@@ -805,7 +813,7 @@ statichere PyTypeObject XChatOut_Type = {
         0,                      /*tp_init*/
         PyType_GenericAlloc,    /*tp_alloc*/
         PyType_GenericNew,      /*tp_new*/
-      	_PyObject_Del,          /*tp_free*/
+      	PyObject_Del,          /*tp_free*/
         0,                      /*tp_is_gc*/
 };
 
@@ -816,7 +824,7 @@ statichere PyTypeObject XChatOut_Type = {
 static void
 Context_dealloc(PyObject *self)
 {
-	self->ob_type->tp_free((PyObject *)self);
+	Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
 static PyObject *
@@ -874,7 +882,7 @@ Context_emit_print(ContextObject *self, PyObject *args)
 					 argv[3], argv[4], argv[5],
 					 argv[6], argv[7], argv[8]);
 	END_XCHAT_CALLS();
-	return PyInt_FromLong(res);
+	return PyLong_FromLong(res);
 }
 
 static PyObject *
@@ -892,7 +900,7 @@ Context_get_info(ContextObject *self, PyObject *args)
 		Py_INCREF(Py_None);
 		return Py_None;
 	}
-	return PyString_FromString(info);
+	return PyUnicode_FromString(info);
 }
 
 static PyObject *
@@ -922,10 +930,10 @@ Context_compare(ContextObject *a, ContextObject *b, int op)
 	else
 	{
 		PyErr_SetString(PyExc_TypeError, "contexts are either equal or not equal");
+		Py_INCREF(Py_None);
 		ret = Py_None;
 	}
 
-	Py_INCREF(ret);
 	return ret;
 }
 
@@ -939,9 +947,8 @@ static PyMethodDef Context_methods[] = {
 	{NULL, NULL}
 };
 
-statichere PyTypeObject Context_Type = {
-	PyObject_HEAD_INIT(NULL)
-	0,			/*ob_size*/
+static PyTypeObject Context_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
 	"hexchat.Context",	/*tp_name*/
 	sizeof(ContextObject),	/*tp_basicsize*/
 	0,			/*tp_itemsize*/
@@ -979,7 +986,7 @@ statichere PyTypeObject Context_Type = {
         0,                      /*tp_init*/
         PyType_GenericAlloc,    /*tp_alloc*/
         PyType_GenericNew,      /*tp_new*/
-      	_PyObject_Del,          /*tp_free*/
+      	PyObject_Del,          /*tp_free*/
         0,                      /*tp_is_gc*/
 };
 
@@ -1025,19 +1032,18 @@ static void
 ListItem_dealloc(PyObject *self)
 {
 	Py_DECREF(((ListItemObject*)self)->dict);
-	self->ob_type->tp_free((PyObject *)self);
+	Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
 static PyObject *
 ListItem_repr(PyObject *self)
 {
-	return PyString_FromFormat("<%s list item at %p>",
+	return PyUnicode_FromFormat("<%s list item at %p>",
 			    	   ((ListItemObject*)self)->listname, self);
 }
 
-statichere PyTypeObject ListItem_Type = {
-	PyObject_HEAD_INIT(NULL)
-	0,			/*ob_size*/
+static PyTypeObject ListItem_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
 	"hexchat.ListItem",	/*tp_name*/
 	sizeof(ListItemObject),	/*tp_basicsize*/
 	0,			/*tp_itemsize*/
@@ -1075,7 +1081,7 @@ statichere PyTypeObject ListItem_Type = {
         0,                      /*tp_init*/
         PyType_GenericAlloc,    /*tp_alloc*/
         PyType_GenericNew,      /*tp_new*/
-      	_PyObject_Del,          /*tp_free*/
+      	PyObject_Del,          /*tp_free*/
         0,                      /*tp_is_gc*/
 };
 
@@ -1110,12 +1116,12 @@ ListItem_New(const char *listname)
 		} \
 		plugin->x = g_strdup(""); \
 	} else {\
-		if (!PyString_Check(o)) { \
+		if (!PyUnicode_Check(o)) { \
 			hexchat_print(ph, "Variable __module_" #x "__ " \
 					"must be a string"); \
 			goto error; \
 		} \
-		plugin->x = g_strdup(PyString_AsString(o)); \
+		plugin->x = g_strdup(PyUnicode_AsUTF8(o)); \
 		if (plugin->x == NULL) { \
 			hexchat_print(ph, "Not enough memory to allocate " #x); \
 			goto error; \
@@ -1123,11 +1129,15 @@ ListItem_New(const char *listname)
 	}
 
 static PyObject *
-Plugin_New(char *filename, PyMethodDef *xchat_methods, PyObject *xcoobj)
+Plugin_New(char *filename, PyObject *xcoobj)
 {
 	PluginObject *plugin = NULL;
-	PyObject *m, *hm, *xm, *o;
-	char *argv[] = {"<xchat>", 0};
+	PyObject *m, *o;
+#ifdef IS_PY3K
+	wchar_t *argv[] = { L"<hexchat>", 0 };
+#else
+	char *argv[] = { "<hexchat>", 0 };
+#endif
 
 	if (filename) {
 		char *old_filename = filename;
@@ -1153,7 +1163,7 @@ Plugin_New(char *filename, PyMethodDef *xchat_methods, PyObject *xcoobj)
 	Plugin_SetContext(plugin, hexchat_get_context(ph));
 
 	/* Start a new interpreter environment for this plugin. */
-	PyEval_AcquireLock();
+	PyEval_AcquireThread(main_tstate);
 	plugin->tstate = Py_NewInterpreter();
 	if (plugin->tstate == NULL) {
 		hexchat_print(ph, "Can't create interpreter state");
@@ -1169,67 +1179,27 @@ Plugin_New(char *filename, PyMethodDef *xchat_methods, PyObject *xcoobj)
 	Py_INCREF(xcoobj);
 	PySys_SetObject("stderr", xcoobj);
 
-	/* Add xchat module to the environment. */
-	xm = Py_InitModule("xchat", xchat_methods);
-	if (xm == NULL) {
-		hexchat_print(ph, "Can't create xchat module");
-		goto error;
-	}
-	hm = Py_InitModule("hexchat", xchat_methods);
-	if (hm == NULL) {
-		hexchat_print(ph, "Can't create hexchat module");
-		goto error;
-	}
-	
-	PyModule_AddIntConstant(xm, "EAT_NONE", HEXCHAT_EAT_NONE);
-	PyModule_AddIntConstant(xm, "EAT_XCHAT", HEXCHAT_EAT_HEXCHAT);
-	PyModule_AddIntConstant(xm, "EAT_PLUGIN", HEXCHAT_EAT_PLUGIN);
-	PyModule_AddIntConstant(xm, "EAT_ALL", HEXCHAT_EAT_ALL);
-	PyModule_AddIntConstant(xm, "PRI_HIGHEST", HEXCHAT_PRI_HIGHEST);
-	PyModule_AddIntConstant(xm, "PRI_HIGH", HEXCHAT_PRI_HIGH);
-	PyModule_AddIntConstant(xm, "PRI_NORM", HEXCHAT_PRI_NORM);
-	PyModule_AddIntConstant(xm, "PRI_LOW", HEXCHAT_PRI_LOW);
-	PyModule_AddIntConstant(xm, "PRI_LOWEST", HEXCHAT_PRI_LOWEST);
-	PyModule_AddIntConstant(hm, "EAT_NONE", HEXCHAT_EAT_NONE);
-	PyModule_AddIntConstant(hm, "EAT_HEXCHAT", HEXCHAT_EAT_HEXCHAT);
-	PyModule_AddIntConstant(hm, "EAT_PLUGIN", HEXCHAT_EAT_PLUGIN);
-	PyModule_AddIntConstant(hm, "EAT_ALL", HEXCHAT_EAT_ALL);
-	PyModule_AddIntConstant(hm, "PRI_HIGHEST", HEXCHAT_PRI_HIGHEST);
-	PyModule_AddIntConstant(hm, "PRI_HIGH", HEXCHAT_PRI_HIGH);
-	PyModule_AddIntConstant(hm, "PRI_NORM", HEXCHAT_PRI_NORM);
-	PyModule_AddIntConstant(hm, "PRI_LOW", HEXCHAT_PRI_LOW);
-	PyModule_AddIntConstant(hm, "PRI_LOWEST", HEXCHAT_PRI_LOWEST);
-
-
-
-	o = Py_BuildValue("(ii)", VERSION_MAJOR, VERSION_MINOR);
-	if (o == NULL) {
-		hexchat_print(ph, "Can't create version tuple");
-		goto error;
-	}
-	PyObject_SetAttrString(xm, "__version__", o);
-	PyObject_SetAttrString(hm, "__version__", o);
-
 	if (filename) {
 #ifdef WIN32
-		PyObject* PyFileObject = PyFile_FromString(filename, "r");
-		if (PyFileObject == NULL) {
+		char *file;
+		if (!g_file_get_contents_utf8(filename, &file, NULL, NULL)) {
 			hexchat_printf(ph, "Can't open file %s: %s\n",
 				     filename, strerror(errno));
 			goto error;
 		}
 
-		if (PyRun_SimpleFile(PyFile_AsFile(PyFileObject), filename) != 0) {
+		if (PyRun_SimpleString(file) != 0) {
 			hexchat_printf(ph, "Error loading module %s\n",
 				     filename);
+			g_free (file);
 			goto error;
 		}
 
 		plugin->filename = filename;
 		filename = NULL;
+		g_free (file);
 #else
 		FILE *fp;
-
 		plugin->filename = filename;
 
 		/* It's now owned by the plugin. */
@@ -1276,7 +1246,11 @@ error:
 
 	if (plugin) {
 		if (plugin->tstate)
-			Py_EndInterpreter(plugin->tstate);
+		{
+			/* FIXME: Handle this? */
+			if (plugin->tstate == PyInterpreterState_ThreadHead(plugin->tstate->interp))
+				Py_EndInterpreter(plugin->tstate);
+		}
 		Py_DECREF(plugin);
 	}
 	PyEval_ReleaseLock();
@@ -1417,12 +1391,11 @@ Plugin_dealloc(PluginObject *self)
 	g_free(self->name);
 	g_free(self->version);
 	g_free(self->description);
-	self->ob_type->tp_free((PyObject *)self);
+	Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
-statichere PyTypeObject Plugin_Type = {
-	PyObject_HEAD_INIT(NULL)
-	0,			/*ob_size*/
+static PyTypeObject Plugin_Type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
 	"hexchat.Plugin",		/*tp_name*/
 	sizeof(PluginObject),	/*tp_basicsize*/
 	0,			/*tp_itemsize*/
@@ -1460,7 +1433,7 @@ statichere PyTypeObject Plugin_Type = {
         0,                      /*tp_init*/
         PyType_GenericAlloc,    /*tp_alloc*/
         PyType_GenericNew,      /*tp_new*/
-      	_PyObject_Del,          /*tp_free*/
+      	PyObject_Del,          /*tp_free*/
         0,                      /*tp_is_gc*/
 };
 
@@ -1511,7 +1484,7 @@ Module_hexchat_emit_print(PyObject *self, PyObject *args)
 					 argv[3], argv[4], argv[5],
 					 argv[6], argv[7], argv[8]);
 	END_XCHAT_CALLS();
-	return PyInt_FromLong(res);
+	return PyLong_FromLong(res);
 }
 
 static PyObject *
@@ -1528,7 +1501,7 @@ Module_hexchat_get_info(PyObject *self, PyObject *args)
 		Py_INCREF(Py_None);
 		return Py_None;
 	}
-	return PyString_FromString(info);
+	return PyUnicode_FromString(info);
 }
 
 static PyObject *
@@ -1550,11 +1523,11 @@ Module_xchat_get_prefs(PyObject *self, PyObject *args)
 			res = Py_None;
 			break;
 		case 1:
-			res = PyString_FromString((char*)info);
+			res = PyUnicode_FromString((char*)info);
 			break;
 		case 2:
 		case 3:
-			res = PyInt_FromLong(integer);
+			res = PyLong_FromLong(integer);
 			break;
 		default:
 			PyErr_Format(PyExc_RuntimeError,
@@ -1608,16 +1581,20 @@ Module_hexchat_pluginpref_set(PyObject *self, PyObject *args)
 	PyObject *value;
 	if (!PyArg_ParseTuple(args, "sO:set_pluginpref", &var, &value))
 		return NULL;
-	if (PyInt_Check(value)) {
-		int intvalue = PyInt_AsLong(value);
-		result = PyInt_FromLong(hexchat_pluginpref_set_int(ph, var, intvalue));
-	}
-	else if (PyString_Check(value)) {
-		char *charvalue = PyString_AsString(value);
-		result = PyInt_FromLong(hexchat_pluginpref_set_str(ph, var, charvalue));
+	if (PyLong_Check(value)) {
+		int intvalue = PyLong_AsLong(value);
+		BEGIN_XCHAT_CALLS(NONE);
+		result = PyLong_FromLong(hexchat_pluginpref_set_int(ph, var, intvalue));
+		END_XCHAT_CALLS();
+	}
+	else if (PyUnicode_Check(value)) {
+		char *charvalue = PyUnicode_AsUTF8(value);
+		BEGIN_XCHAT_CALLS(NONE);
+		result = PyLong_FromLong(hexchat_pluginpref_set_str(ph, var, charvalue));
+		END_XCHAT_CALLS();
 	}
 	else
-		result = PyInt_FromLong(0);
+		result = PyLong_FromLong(0);
 	return result;
 }
 
@@ -1628,20 +1605,27 @@ Module_hexchat_pluginpref_get(PyObject *self, PyObject *args)
 	char *var;
 	char retstr[512];
 	int retint;
+	int result;
 	if (!PyArg_ParseTuple(args, "s:get_pluginpref", &var))
 		return NULL;
 	// This will always return numbers as integers.
-	if (hexchat_pluginpref_get_str(ph, var, retstr)) {
+	BEGIN_XCHAT_CALLS(NONE);
+	result = hexchat_pluginpref_get_str(ph, var, retstr);
+	END_XCHAT_CALLS();
+	if (result) {
 		if (strlen (retstr) <= 12) {
+			BEGIN_XCHAT_CALLS(NONE);
 			retint = hexchat_pluginpref_get_int(ph, var);
+			END_XCHAT_CALLS();
 			if ((retint == 0) && (strcmp(retstr, "0") != 0))
-				ret = PyString_FromString(retstr);
+				ret = PyUnicode_FromString(retstr);
 			else
-				ret = PyInt_FromLong(retint);
+				ret = PyLong_FromLong(retint);
 		} else
-			ret = PyString_FromString(retstr);
+			ret = PyUnicode_FromString(retstr);
 	}
 	else
+		Py_INCREF(Py_None);
 		ret = Py_None;
 	return ret;
 }
@@ -1653,8 +1637,10 @@ Module_hexchat_pluginpref_delete(PyObject *self, PyObject *args)
 	int result;
 	if (!PyArg_ParseTuple(args, "s:del_pluginpref", &var))
 		return NULL;
+	BEGIN_XCHAT_CALLS(NONE);
 	result = hexchat_pluginpref_delete(ph, var);
-	return PyInt_FromLong(result);
+	END_XCHAT_CALLS();
+	return PyLong_FromLong(result);
 }
 
 static PyObject *
@@ -1662,12 +1648,16 @@ Module_hexchat_pluginpref_list(PyObject *self, PyObject *args)
 {
 	char list[512];
 	char* token;
+	int result;
 	PyObject *pylist;
 	pylist = PyList_New(0);
-	if (hexchat_pluginpref_list(ph, list)) {
+	BEGIN_XCHAT_CALLS(NONE);
+	result = hexchat_pluginpref_list(ph, list);
+	END_XCHAT_CALLS();
+	if (result) {
 		token = strtok(list, ",");
 		while (token != NULL) {
-			PyList_Append(pylist, PyString_FromString(token));
+			PyList_Append(pylist, PyUnicode_FromString(token));
 			token = strtok (NULL, ",");
 		}
 	}
@@ -1709,7 +1699,7 @@ Module_hexchat_hook_command(PyObject *self, PyObject *args, PyObject *kwargs)
 					       Callback_Command, help, hook);
 	END_XCHAT_CALLS();
 
-	return PyInt_FromLong((long)hook);
+	return PyLong_FromLong((long)hook);
 }
 
 static PyObject *
@@ -1745,7 +1735,7 @@ Module_hexchat_hook_server(PyObject *self, PyObject *args, PyObject *kwargs)
 					      Callback_Command, hook);
 	END_XCHAT_CALLS();
 
-	return PyInt_FromLong((long)hook);
+	return PyLong_FromLong((long)hook);
 }
 
 static PyObject *
@@ -1781,10 +1771,9 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs)
 					     Callback_Print, hook);
 	END_XCHAT_CALLS();
 
-	return PyInt_FromLong((long)hook);
+	return PyLong_FromLong((long)hook);
 }
 
-
 static PyObject *
 Module_hexchat_hook_timer(PyObject *self, PyObject *args, PyObject *kwargs)
 {
@@ -1817,7 +1806,7 @@ Module_hexchat_hook_timer(PyObject *self, PyObject *args, PyObject *kwargs)
 					     Callback_Timer, hook);
 	END_XCHAT_CALLS();
 
-	return PyInt_FromLong((long)hook);
+	return PyLong_FromLong((long)hook);
 }
 
 static PyObject *
@@ -1845,7 +1834,7 @@ Module_hexchat_hook_unload(PyObject *self, PyObject *args, PyObject *kwargs)
 	if (hook == NULL)
 		return NULL;
 
-	return PyInt_FromLong((long)hook);
+	return PyLong_FromLong((long)hook);
 }
 
 static PyObject *
@@ -1911,11 +1900,11 @@ Module_xchat_get_list(PyObject *self, PyObject *args)
 			switch(fields[i][0]) {
 			case 's':
 				sattr = hexchat_list_str(ph, list, (char*)fld);
-				attr = PyString_FromString(sattr?sattr:"");
+				attr = PyUnicode_FromString(sattr?sattr:"");
 				break;
 			case 'i':
 				iattr = hexchat_list_int(ph, list, (char*)fld);
-				attr = PyInt_FromLong((long)iattr);
+				attr = PyLong_FromLong((long)iattr);
 				break;
 			case 'p':
 				sattr = hexchat_list_str(ph, list, (char*)fld);
@@ -1959,7 +1948,7 @@ Module_xchat_get_lists(PyObject *self, PyObject *args)
 	if (l == NULL)
 		return NULL;
 	for (i = 0; fields[i]; i++) {
-		o = PyString_FromString(fields[i]);
+		o = PyUnicode_FromString(fields[i]);
 		if (o == NULL || PyList_Append(l, o) == -1) {
 			Py_DECREF(l);
 			Py_XDECREF(o);
@@ -1976,7 +1965,7 @@ Module_hexchat_nickcmp(PyObject *self, PyObject *args)
 	char *s1, *s2;
 	if (!PyArg_ParseTuple(args, "ss:nickcmp", &s1, &s2))
 		return NULL;
-	return PyInt_FromLong((long) hexchat_nickcmp(ph, s1, s2));
+	return PyLong_FromLong((long) hexchat_nickcmp(ph, s1, s2));
 }
 
 static PyObject *
@@ -1988,7 +1977,7 @@ Module_hexchat_strip(PyObject *self, PyObject *args)
 	if (!PyArg_ParseTuple(args, "s|ii:strip", &str, &len, &flags))
 		return NULL;
 	str2 = hexchat_strip(ph, str, len, flags);
-	result = PyString_FromString(str2);
+	result = PyUnicode_FromString(str2);
 	hexchat_free(ph, str2);
 	return result;
 }
@@ -2039,6 +2028,106 @@ static PyMethodDef Module_xchat_methods[] = {
 	{NULL, NULL}
 };
 
+#ifdef IS_PY3K
+static struct PyModuleDef moduledef = {
+	PyModuleDef_HEAD_INIT,
+	"hexchat",     /* m_name */
+	"HexChat Scripting Interface",  /* m_doc */
+	-1,                  /* m_size */
+	Module_xchat_methods,    /* m_methods */
+	NULL,                /* m_reload */
+	NULL,                /* m_traverse */
+	NULL,                /* m_clear */
+	NULL,                /* m_free */
+};
+
+static struct PyModuleDef xchat_moduledef = {
+	PyModuleDef_HEAD_INIT,
+	"xchat",     /* m_name */
+	"HexChat Scripting Interface",  /* m_doc */
+	-1,                  /* m_size */
+	Module_xchat_methods,    /* m_methods */
+	NULL,                /* m_reload */
+	NULL,                /* m_traverse */
+	NULL,                /* m_clear */
+	NULL,                /* m_free */
+};
+#endif
+
+static PyObject *
+moduleinit_hexchat(void)
+{
+	PyObject *hm;
+#ifdef IS_PY3K
+		hm = PyModule_Create(&moduledef);
+#else
+    hm = Py_InitModule3("hexchat", Module_xchat_methods, "HexChat Scripting Interface");
+#endif
+
+	PyModule_AddIntConstant(hm, "EAT_NONE", HEXCHAT_EAT_NONE);
+	PyModule_AddIntConstant(hm, "EAT_HEXCHAT", HEXCHAT_EAT_HEXCHAT);
+	PyModule_AddIntConstant(hm, "EAT_XCHAT", HEXCHAT_EAT_HEXCHAT); /* for compat */
+	PyModule_AddIntConstant(hm, "EAT_PLUGIN", HEXCHAT_EAT_PLUGIN);
+	PyModule_AddIntConstant(hm, "EAT_ALL", HEXCHAT_EAT_ALL);
+	PyModule_AddIntConstant(hm, "PRI_HIGHEST", HEXCHAT_PRI_HIGHEST);
+	PyModule_AddIntConstant(hm, "PRI_HIGH", HEXCHAT_PRI_HIGH);
+	PyModule_AddIntConstant(hm, "PRI_NORM", HEXCHAT_PRI_NORM);
+	PyModule_AddIntConstant(hm, "PRI_LOW", HEXCHAT_PRI_LOW);
+	PyModule_AddIntConstant(hm, "PRI_LOWEST", HEXCHAT_PRI_LOWEST);
+
+	PyObject_SetAttrString(hm, "__version__", Py_BuildValue("(ii)", VERSION_MAJOR, VERSION_MINOR));
+
+	return hm;
+}
+
+static PyObject *
+moduleinit_xchat(void)
+{
+	PyObject *xm;
+#ifdef IS_PY3K
+		xm = PyModule_Create(&xchat_moduledef);
+#else
+    xm = Py_InitModule3("xchat", Module_xchat_methods, "HexChat Scripting Interface");
+#endif
+
+	PyModule_AddIntConstant(xm, "EAT_NONE", HEXCHAT_EAT_NONE);
+	PyModule_AddIntConstant(xm, "EAT_XCHAT", HEXCHAT_EAT_HEXCHAT);
+	PyModule_AddIntConstant(xm, "EAT_PLUGIN", HEXCHAT_EAT_PLUGIN);
+	PyModule_AddIntConstant(xm, "EAT_ALL", HEXCHAT_EAT_ALL);
+	PyModule_AddIntConstant(xm, "PRI_HIGHEST", HEXCHAT_PRI_HIGHEST);
+	PyModule_AddIntConstant(xm, "PRI_HIGH", HEXCHAT_PRI_HIGH);
+	PyModule_AddIntConstant(xm, "PRI_NORM", HEXCHAT_PRI_NORM);
+	PyModule_AddIntConstant(xm, "PRI_LOW", HEXCHAT_PRI_LOW);
+	PyModule_AddIntConstant(xm, "PRI_LOWEST", HEXCHAT_PRI_LOWEST);
+
+	PyObject_SetAttrString(xm, "__version__", Py_BuildValue("(ii)", VERSION_MAJOR, VERSION_MINOR));
+
+	return xm;
+}
+
+#ifdef IS_PY3K
+PyMODINIT_FUNC
+PyInit_hexchat(void)
+{
+    return moduleinit_hexchat();
+}
+PyMODINIT_FUNC
+PyInit_xchat(void)
+{
+    return moduleinit_xchat();
+}
+#else
+PyMODINIT_FUNC
+inithexchat(void)
+{
+		moduleinit_hexchat();
+}
+PyMODINIT_FUNC
+initxchat(void)
+{
+		moduleinit_xchat();
+}
+#endif
 
 /* ===================================================================== */
 /* Python interactive interpreter functions */
@@ -2046,18 +2135,18 @@ static PyMethodDef Module_xchat_methods[] = {
 static void
 IInterp_Exec(char *command)
 {
-        PyObject *m, *d, *o;
+	PyObject *m, *d, *o;
 	char *buffer;
 	int len;
 
 	BEGIN_PLUGIN(interp_plugin);
 
-        m = PyImport_AddModule("__main__");
-        if (m == NULL) {
+	m = PyImport_AddModule("__main__");
+	if (m == NULL) {
 		hexchat_print(ph, "Can't get __main__ module");
 		goto fail;
 	}
-        d = PyModule_GetDict(m);
+	d = PyModule_GetDict(m);
 	len = strlen(command);
 	buffer = (char *) g_malloc(len+2);
 	if (buffer == NULL) {
@@ -2067,20 +2156,17 @@ IInterp_Exec(char *command)
 	memcpy(buffer, command, len);
 	buffer[len] = '\n';
 	buffer[len+1] = 0;
-        o = PyRun_StringFlags(buffer, Py_single_input, d, d, NULL);
+	o = PyRun_StringFlags(buffer, Py_single_input, d, d, NULL);
 	g_free(buffer);
-        if (o == NULL) {
-                PyErr_Print();
+	if (o == NULL) {
+		PyErr_Print();
 		goto fail;
-        }
-        Py_DECREF(o);
-        if (Py_FlushLine())
-                PyErr_Clear();
+	}
+	Py_DECREF(o);
 
 fail:
 	END_PLUGIN(interp_plugin);
-
-        return;
+	return;
 }
 
 static int
@@ -2132,7 +2218,7 @@ Command_PyLoad(char *filename)
 {
 	PyObject *plugin;
 	RELEASE_XCHAT_LOCK();
-	plugin = Plugin_New(filename, Module_xchat_methods, xchatout);
+	plugin = Plugin_New(filename, xchatout);
 	ACQUIRE_XCHAT_LOCK();
 	if (plugin)
 		plugin_list = g_slist_append(plugin_list, plugin);
@@ -2162,7 +2248,6 @@ Command_PyReload(char *name)
 		char *filename = g_strdup(plugin->filename);
 		Command_PyUnload(filename);
 		Command_PyLoad(filename);
-		/* cppcheck-suppress deallocDealloc */
 		g_free(filename);
 	}
 }
@@ -2225,22 +2310,22 @@ Command_Load(char *word[], char *word_eol[], void *userdata)
 }
 
 static int
-Command_Unload(char *word[], char *word_eol[], void *userdata)
+Command_Reload(char *word[], char *word_eol[], void *userdata)
 {
 	int len = strlen(word[2]);
 	if (len > 3 && strcasecmp(".py", word[2]+len-3) == 0) {
-		Command_PyUnload(word[2]);
-		return HEXCHAT_EAT_HEXCHAT;
+	Command_PyReload(word[2]);
+	return HEXCHAT_EAT_HEXCHAT;
 	}
 	return HEXCHAT_EAT_NONE;
 }
 
 static int
-Command_Reload(char *word[], char *word_eol[], void *userdata)
+Command_Unload(char *word[], char *word_eol[], void *userdata)
 {
 	int len = strlen(word[2]);
 	if (len > 3 && strcasecmp(".py", word[2]+len-3) == 0) {
-		Command_PyReload(word[2]);
+		Command_PyUnload(word[2]);
 		return HEXCHAT_EAT_HEXCHAT;
 	}
 	return HEXCHAT_EAT_NONE;
@@ -2272,7 +2357,11 @@ hexchat_plugin_init(hexchat_plugin *plugin_handle,
 		  char **plugin_version,
 		  char *arg)
 {
-	char *argv[] = {"<xchat>", 0};
+#ifdef IS_PY3K
+	wchar_t *argv[] = { L"<hexchat>", 0 };
+#else
+	char *argv[] = { "<hexchat>", 0 };
+#endif
 
 	ph = plugin_handle;
 
@@ -2291,14 +2380,18 @@ hexchat_plugin_init(hexchat_plugin *plugin_handle,
 	*plugin_desc = "Python scripting interface";
 
 	/* Initialize python. */
-	Py_SetProgramName("xchat");
+#ifdef IS_PY3K
+	Py_SetProgramName(L"hexchat");
+	PyImport_AppendInittab("hexchat", PyInit_hexchat);
+	PyImport_AppendInittab("xchat", PyInit_xchat);
+#else
+	Py_SetProgramName("hexchat");
+	PyImport_AppendInittab("hexchat", inithexchat);
+	PyImport_AppendInittab("xchat", initxchat);
+#endif
 	Py_Initialize();
 	PySys_SetArgv(1, argv);
 
-	Plugin_Type.ob_type = &PyType_Type;
-	Context_Type.ob_type = &PyType_Type;
-	XChatOut_Type.ob_type = &PyType_Type;
-
 	xchatout = XChatOut_New();
 	if (xchatout == NULL) {
 		hexchat_print(ph, "Can't allocate xchatout object");
@@ -2309,7 +2402,7 @@ hexchat_plugin_init(hexchat_plugin *plugin_handle,
 	PyEval_InitThreads();
 	xchat_lock = PyThread_allocate_lock();
 	if (xchat_lock == NULL) {
-		hexchat_print(ph, "Can't allocate xchat lock");
+		hexchat_print(ph, "Can't allocate hexchat lock");
 		Py_DECREF(xchatout);
 		xchatout = NULL;
 		return 0;
@@ -2318,7 +2411,7 @@ hexchat_plugin_init(hexchat_plugin *plugin_handle,
 
 	main_tstate = PyEval_SaveThread();
 
-	interp_plugin = Plugin_New(NULL, Module_xchat_methods, xchatout);
+	interp_plugin = Plugin_New(NULL, xchatout);
 	if (interp_plugin == NULL) {
 		hexchat_print(ph, "Plugin_New() failed.\n");
 #ifdef WITH_THREAD
@@ -2381,6 +2474,7 @@ hexchat_plugin_deinit()
 
 	/* Switch back to the main thread state. */
 	if (main_tstate) {
+		PyEval_RestoreThread(main_tstate);
 		PyThreadState_Swap(main_tstate);
 		main_tstate = NULL;
 	}
diff --git a/plugins/python/python.vcxproj b/plugins/python/python2.vcxproj
index 6d95d056..e2153c4a 100644
--- a/plugins/python/python.vcxproj
+++ b/plugins/python/python2.vcxproj
@@ -16,7 +16,7 @@
   <PropertyGroup Label="Globals">

     <ProjectGuid>{19C52A0A-A790-409E-A28A-9745FF990F5C}</ProjectGuid>

     <Keyword>Win32Proj</Keyword>

-    <RootNamespace>python</RootNamespace>

+    <RootNamespace>python2</RootNamespace>

   </PropertyGroup>

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

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

@@ -51,7 +51,7 @@
   </PropertyGroup>

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

     <LinkIncremental>false</LinkIncremental>

-    <TargetName>$(PythonOutput)</TargetName>

+    <TargetName>$(Python2Output)</TargetName>

     <OutDir>$(HexChatBin)</OutDir>

     <IntDir>$(HexChatObj)$(ProjectName)\</IntDir>

   </PropertyGroup>

@@ -63,7 +63,7 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

-      <AdditionalIncludeDirectories>$(Glib);$(PythonPath)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(Glib);$(Python2Path)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

     </ClCompile>

     <Link>

@@ -72,8 +72,8 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>

       <OptimizeReferences>true</OptimizeReferences>

       <ModuleDefinitionFile>python.def</ModuleDefinitionFile>

-      <AdditionalDependencies>"$(PythonLib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

-      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(PythonPath)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+      <AdditionalDependencies>"$(Python2Lib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(Python2Path)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

     </Link>

   </ItemDefinitionGroup>

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

@@ -84,7 +84,7 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>

       <IntrinsicFunctions>true</IntrinsicFunctions>

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

-      <AdditionalIncludeDirectories>$(Glib);$(PythonPath)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories>$(Glib);$(Python2Path)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

       <MultiProcessorCompilation>true</MultiProcessorCompilation>

     </ClCompile>

     <Link>

@@ -93,8 +93,8 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>

       <OptimizeReferences>true</OptimizeReferences>

       <ModuleDefinitionFile>python.def</ModuleDefinitionFile>

-      <AdditionalDependencies>"$(PythonLib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

-      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(PythonPath)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+      <AdditionalDependencies>"$(Python2Lib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(Python2Path)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

     </Link>

   </ItemDefinitionGroup>

   <ItemGroup>

diff --git a/plugins/python/python.vcxproj.filters b/plugins/python/python2.vcxproj.filters
index d56e53b6..d56e53b6 100644
--- a/plugins/python/python.vcxproj.filters
+++ b/plugins/python/python2.vcxproj.filters
diff --git a/plugins/python/python3.vcxproj b/plugins/python/python3.vcxproj
new file mode 100644
index 00000000..ddf56132
--- /dev/null
+++ b/plugins/python/python3.vcxproj
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>

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

+  <PropertyGroup Label="Configuration">

+    <PlatformToolset>v110</PlatformToolset>

+  </PropertyGroup>

+  <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">

+    <ProjectGuid>{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>python3</RootNamespace>

+  </PropertyGroup>

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

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

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>MultiByte</CharacterSet>

+  </PropertyGroup>

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

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>MultiByte</CharacterSet>

+  </PropertyGroup>

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

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

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

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

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

+  </ImportGroup>

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

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

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

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

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

+    <LinkIncremental>false</LinkIncremental>

+    <TargetName>$(Python3Output)</TargetName>

+    <OutDir>$(HexChatBin)</OutDir>

+    <IntDir>$(HexChatObj)$(ProjectName)\</IntDir>

+  </PropertyGroup>

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

+    <LinkIncremental>false</LinkIncremental>

+    <TargetName>$(Python3Output)</TargetName>

+    <OutDir>$(HexChatBin)</OutDir>

+    <IntDir>$(HexChatObj)$(ProjectName)\</IntDir>

+  </PropertyGroup>

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

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

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

+      <AdditionalIncludeDirectories>$(Glib);$(Python3Path)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+    </ClCompile>

+    <Link>

+      <SubSystem>Windows</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <ModuleDefinitionFile>python.def</ModuleDefinitionFile>

+      <AdditionalDependencies>"$(Python3Lib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(Python3Path)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+    </Link>

+  </ItemDefinitionGroup>

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

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

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

+      <AdditionalIncludeDirectories>$(Glib);$(Python3Path)\include;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <MultiProcessorCompilation>true</MultiProcessorCompilation>

+    </ClCompile>

+    <Link>

+      <SubSystem>Windows</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <ModuleDefinitionFile>python.def</ModuleDefinitionFile>

+      <AdditionalDependencies>"$(Python3Lib).lib";$(DepLibs);%(AdditionalDependencies)</AdditionalDependencies>

+      <AdditionalLibraryDirectories>$(DepsRoot)\lib;$(OutDir);$(Python3Path)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <None Include="python.def" />

+  </ItemGroup>

+  <ItemGroup>

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

+  </ItemGroup>

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

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
\ No newline at end of file
diff --git a/plugins/python/python3.vcxproj.filters b/plugins/python/python3.vcxproj.filters
new file mode 100644
index 00000000..9165e798
--- /dev/null
+++ b/plugins/python/python3.vcxproj.filters
@@ -0,0 +1,21 @@
+<?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>{f4eaf231-f095-42d3-8427-b2b6006cacb1}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{0166c0f9-7968-4a09-9ef5-a5179c7746eb}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="python.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <None Include="python.def">

+      <Filter>Resource Files</Filter>

+    </None>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/src/common/plugin.c b/src/common/plugin.c
index a9955327..c9183ede 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -489,7 +489,8 @@ plugin_auto_load (session *sess)
 	for_files (HEXCHATLIBDIR, "hcfishlim.dll", plugin_auto_load_cb);
 	for_files (HEXCHATLIBDIR, "hcmpcinfo.dll", plugin_auto_load_cb);
 	for_files (HEXCHATLIBDIR, "hcperl.dll", plugin_auto_load_cb);
-	for_files (HEXCHATLIBDIR, "hcpython.dll", plugin_auto_load_cb);
+	for_files (HEXCHATLIBDIR, "hcpython2.dll", plugin_auto_load_cb);
+	for_files (HEXCHATLIBDIR, "hcpython3.dll", plugin_auto_load_cb);
 	for_files (HEXCHATLIBDIR, "hcupd.dll", plugin_auto_load_cb);
 	for_files (HEXCHATLIBDIR, "hcwinamp.dll", plugin_auto_load_cb);
 	for_files (HEXCHATLIBDIR, "hcsysinfo.dll", plugin_auto_load_cb);
diff --git a/win32/hexchat.props b/win32/hexchat.props
index 5feac5ad..4da1a3ff 100644
--- a/win32/hexchat.props
+++ b/win32/hexchat.props
@@ -10,7 +10,8 @@
 		<YourGendefPath>c:\mozilla-build\gendef</YourGendefPath>

 		<YourMsgfmtPath>c:\mozilla-build\msgfmt</YourMsgfmtPath>

 		<YourPerlPath>c:\mozilla-build\perl-5.18</YourPerlPath>

-		<YourPythonPath>c:\mozilla-build\python-2.7</YourPythonPath>

+		<YourPython2Path>c:\mozilla-build\python-2.7</YourPython2Path>

+		<YourPython3Path>c:\mozilla-build\python-3.3</YourPython3Path>

 

 		<!-- YOU SHOULDN'T TOUCH ANYTHING BELOW -->

 

@@ -22,9 +23,12 @@
 		<PerlPath>$(YourPerlPath)\$(PlatformName)</PerlPath>

 		<PerlLib>perl517</PerlLib>

 		<PerlOutput>hcperl</PerlOutput>

-		<PythonPath>$(YourPythonPath)\$(PlatformName)</PythonPath>

-		<PythonLib>python27</PythonLib>

-		<PythonOutput>hcpython</PythonOutput>

+		<Python2Path>$(YourPython2Path)\$(PlatformName)</Python2Path>

+		<Python2Lib>python27</Python2Lib>

+		<Python2Output>hcpython2</Python2Output>

+		<Python3Path>$(YourPython3Path)\$(PlatformName)</Python3Path>

+		<Python3Lib>python33</Python3Lib>

+		<Python3Output>hcpython3</Python3Output>

 		<Glib>$(DepsRoot)\include\glib-2.0;$(DepsRoot)\lib\glib-2.0\include;$(DepsRoot)\include\libxml2</Glib>

 		<Gtk>$(DepsRoot)\include\gtk-2.0;$(DepsRoot)\lib\gtk-2.0\include;$(DepsRoot)\include\atk-1.0;$(DepsRoot)\include\cairo;$(DepsRoot)\include\pango-1.0;$(DepsRoot)\include\gdk-pixbuf-2.0</Gtk>

 		<Pixmaps>png_ulist_voice "$(SolutionDir)\..\src\pixmaps\ulist_voice.png" png_ulist_halfop "$(SolutionDir)\..\src\pixmaps\ulist_halfop.png" png_ulist_op "$(SolutionDir)\..\src\pixmaps\ulist_op.png" png_ulist_owner "$(SolutionDir)\..\src\pixmaps\ulist_owner.png" png_ulist_founder "$(SolutionDir)\..\src\pixmaps\ulist_founder.png" png_ulist_netop "$(SolutionDir)\..\src\pixmaps\ulist_netop.png" png_tray_fileoffer "$(SolutionDir)\..\src\pixmaps\tray_fileoffer.png" png_tray_highlight "$(SolutionDir)\..\src\pixmaps\tray_highlight.png" png_tray_message "$(SolutionDir)\..\src\pixmaps\tray_message.png" png_tree_channel "$(SolutionDir)\..\src\pixmaps\tree_channel.png" png_tree_dialog "$(SolutionDir)\..\src\pixmaps\tree_dialog.png" png_tree_server "$(SolutionDir)\..\src\pixmaps\tree_server.png" png_tree_util "$(SolutionDir)\..\src\pixmaps\tree_util.png" png_book "$(SolutionDir)\..\src\pixmaps\book.png" png_hexchat "$(SolutionDir)\..\src\pixmaps\hexchat.png"</Pixmaps>

@@ -82,7 +86,8 @@ copy "$(HexChatBin)hcexec.dll" "$(HexChatRel)\plugins"
 copy "$(HexChatBin)hcfishlim.dll" "$(HexChatRel)\plugins"

 copy "$(HexChatBin)hcmpcinfo.dll" "$(HexChatRel)\plugins"

 copy "$(HexChatBin)hcperl.dll" "$(HexChatRel)\plugins"

-copy "$(HexChatBin)hcpython.dll" "$(HexChatRel)\plugins"

+copy "$(HexChatBin)hcpython2.dll" "$(HexChatRel)\plugins"

+copy "$(HexChatBin)hcpython3.dll" "$(HexChatRel)\plugins"

 copy "$(HexChatBin)hcupd.dll" "$(HexChatRel)\plugins"

 copy "$(HexChatBin)hcwinamp.dll" "$(HexChatRel)\plugins"

 copy "$(HexChatBin)hcsysinfo.dll" "$(HexChatRel)\plugins"

diff --git a/win32/hexchat.sln b/win32/hexchat.sln
index 4bc940e3..cba64c36 100644
--- a/win32/hexchat.sln
+++ b/win32/hexchat.sln
@@ -1,6 +1,6 @@
 

 Microsoft Visual Studio Solution File, Format Version 12.00

-# Visual Studio Express 2012 for Windows Desktop

+# Visual Studio 2012

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "..\src\common\common.vcxproj", "{87554B59-006C-4D94-9714-897B27067BA3}"

 	ProjectSection(ProjectDependencies) = postProject

 		{A7D7CE59-2A31-48AE-BED2-A9828E241832} = {A7D7CE59-2A31-48AE-BED2-A9828E241832}

@@ -30,7 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripting", "scripting", "{
 EndProject

 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{BB051F0F-A841-4A9A-BAF6-51DD9866D65A}"

 EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python", "..\plugins\python\python.vcxproj", "{19C52A0A-A790-409E-A28A-9745FF990F5C}"

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python2", "..\plugins\python\python2.vcxproj", "{19C52A0A-A790-409E-A28A-9745FF990F5C}"

 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doat", "..\plugins\doat\doat.vcxproj", "{4980AF24-9D42-427D-A8E6-0DF3B97C455D}"

 EndProject

@@ -87,6 +87,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make-te", "..\src\common\ma
 EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "perl", "..\plugins\perl\perl.vcxproj", "{D90BC3E3-1341-4849-9354-5F40489D39D1}"

 EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python3", "..\plugins\python\python3.vcxproj", "{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}"

+EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Release|Win32 = Release|Win32

@@ -179,6 +181,10 @@ Global
 		{D90BC3E3-1341-4849-9354-5F40489D39D1}.Release|Win32.Build.0 = Release|Win32

 		{D90BC3E3-1341-4849-9354-5F40489D39D1}.Release|x64.ActiveCfg = Release|x64

 		{D90BC3E3-1341-4849-9354-5F40489D39D1}.Release|x64.Build.0 = Release|x64

+		{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}.Release|Win32.ActiveCfg = Release|Win32

+		{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}.Release|Win32.Build.0 = Release|Win32

+		{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}.Release|x64.ActiveCfg = Release|x64

+		{C2321A03-0BA7-45B3-8740-ABD82B36B0BF}.Release|x64.Build.0 = Release|x64

 	EndGlobalSection

 	GlobalSection(SolutionProperties) = preSolution

 		HideSolutionNode = FALSE

@@ -203,6 +209,7 @@ Global
 		{3024CF36-85E5-4E00-9608-7002E2C7EF14} = {561126F4-FA18-45FC-A2BF-8F858F161D6D}

 		{19C52A0A-A790-409E-A28A-9745FF990F5C} = {D237DA6B-BD5F-46C0-8BEA-50E9A1340240}

 		{D90BC3E3-1341-4849-9354-5F40489D39D1} = {D237DA6B-BD5F-46C0-8BEA-50E9A1340240}

+		{C2321A03-0BA7-45B3-8740-ABD82B36B0BF} = {D237DA6B-BD5F-46C0-8BEA-50E9A1340240}

 		{B10A2C41-344C-43E0-A32D-B9587C198D8B} = {0FD996A7-464F-4981-8380-3DCA3A244A13}

 		{C9B735E4-75BC-45AC-A5E3-39A6D076F912} = {0FD996A7-464F-4981-8380-3DCA3A244A13}

 		{5A0F4962-E670-4DA2-9E45-52CC47F26E2F} = {0FD996A7-464F-4981-8380-3DCA3A244A13}

diff --git a/win32/installer/hexchat-x64.skel.iss b/win32/installer/hexchat-x64.skel.iss
index d742fdfa..64b1b2e7 100644
--- a/win32/installer/hexchat-x64.skel.iss
+++ b/win32/installer/hexchat-x64.skel.iss
@@ -47,7 +47,9 @@ Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags:
 Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning
 Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
 Name: "langs\perl"; Description: "Perl (requires Perl 5.18)"; Types: custom; Flags: disablenouninstallwarning
-Name: "langs\python"; Description: "Python (requires Python 2.7)"; Types: custom; Flags: disablenouninstallwarning
+Name: "langs\python"; Description: "Python Interface"; Types: custom; Flags: disablenouninstallwarning
+Name: "langs\python\python2"; Description: "Python (requires Python 2.7)"; Types: custom; Flags: disablenouninstallwarning exclusive
+Name: "langs\python\python3"; Description: "Python (requires Python 3.3)"; Types: custom; Flags: disablenouninstallwarning exclusive
 
 [Tasks]
 Name: portable; Description: "Yes"; GroupDescription: "Portable Install (no Registry entries, no Start Menu icons, no uninstaller):"; Flags: unchecked
@@ -71,9 +73,9 @@ Root: HKCR; Subkey: ".hct\shell\open\command"; ValueType: string; ValueName: "";
 Filename: "{app}\hexchat.exe"; Description: "Run HexChat after closing the Wizard"; Flags: nowait postinstall skipifsilent
 Filename: "http://www.microsoft.com/en-us/download/details.aspx?id=30679"; Description: "Download Visual C++ 2012 Update 1 Redistributable"; Flags: shellexec runasoriginaluser postinstall skipifsilent
 Filename: "http://docs.hexchat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl 5.18"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and not langs\python
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Python 2.7"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\python and not langs\perl
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl 5.18 and Python 2.7"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and langs\python
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and not langs\python
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\python and not langs\perl
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl and Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and langs\python
 
 [Files]
 Source: "portable-mode"; DestDir: "{app}"; Tasks: portable
@@ -145,7 +147,8 @@ Source: "plugins\hcwinamp.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion;
 Source: "share\system.png"; DestDir: "{app}\share"; Flags: ignoreversion; Components: plugins\sysinfo
 Source: "plugins\hcsysinfo.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\sysinfo
 
-Source: "plugins\hcpython.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python
+Source: "plugins\hcpython2.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python\python2
+Source: "plugins\hcpython3.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python\python3
 Source: "plugins\hcperl.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\perl
 
 Source: "hexchat.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs
diff --git a/win32/installer/hexchat-x86.skel.iss b/win32/installer/hexchat-x86.skel.iss
index fa86cd0c..10e9d277 100644
--- a/win32/installer/hexchat-x86.skel.iss
+++ b/win32/installer/hexchat-x86.skel.iss
@@ -46,7 +46,9 @@ Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags:
 Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning
 Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
 Name: "langs\perl"; Description: "Perl (requires Perl 5.18)"; Types: custom; Flags: disablenouninstallwarning
-Name: "langs\python"; Description: "Python (requires Python 2.7)"; Types: custom; Flags: disablenouninstallwarning
+Name: "langs\python"; Description: "Python Interface"; Types: custom; Flags: disablenouninstallwarning
+Name: "langs\python\python2"; Description: "Python (requires Python 2.7)"; Types: custom; Flags: disablenouninstallwarning exclusive
+Name: "langs\python\python3"; Description: "Python (requires Python 3.3)"; Types: custom; Flags: disablenouninstallwarning exclusive
 
 [Tasks]
 Name: portable; Description: "Yes"; GroupDescription: "Portable Install (no Registry entries, no Start Menu icons, no uninstaller):"; Flags: unchecked
@@ -70,9 +72,9 @@ Root: HKCR; Subkey: ".hct\shell\open\command"; ValueType: string; ValueName: "";
 Filename: "{app}\hexchat.exe"; Description: "Run HexChat after closing the Wizard"; Flags: nowait postinstall skipifsilent
 Filename: "http://www.microsoft.com/en-us/download/details.aspx?id=30679"; Description: "Download Visual C++ 2012 Update 1 Redistributable"; Flags: shellexec runasoriginaluser postinstall skipifsilent
 Filename: "http://docs.hexchat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl 5.18"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and not langs\python
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Python 2.7"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\python and not langs\perl
-Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl 5.18 and Python 2.7"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and langs\python
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and not langs\python
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\python and not langs\perl
+Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl and Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and langs\python
 
 [Files]
 Source: "portable-mode"; DestDir: "{app}"; Tasks: portable
@@ -144,7 +146,8 @@ Source: "plugins\hcwinamp.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion;
 Source: "share\system.png"; DestDir: "{app}\share"; Flags: ignoreversion; Components: plugins\sysinfo
 Source: "plugins\hcsysinfo.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\sysinfo
 
-Source: "plugins\hcpython.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python
+Source: "plugins\hcpython2.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python\python2
+Source: "plugins\hcpython3.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\python\python3
 Source: "plugins\hcperl.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\perl
 
 Source: "hexchat.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs