about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/callbacks.c14
-rw-r--r--src/plugins/python_api.c377
-rw-r--r--src/plugins/python_api.h4
-rw-r--r--src/plugins/python_plugins.c182
4 files changed, 320 insertions, 257 deletions
diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c
index c59211ba..bfe8a3c6 100644
--- a/src/plugins/callbacks.c
+++ b/src/plugins/callbacks.c
@@ -159,13 +159,15 @@ callbacks_remove(const char *const plugin_name)
     g_hash_table_remove(p_timed_functions, plugin_name);
 
     GHashTable *tag_to_win_cb_hash = g_hash_table_lookup(p_window_callbacks, plugin_name);
-    GList *tags = g_hash_table_get_keys(tag_to_win_cb_hash);
-    GList *curr = tags;
-    while (curr) {
-        wins_close_plugin(curr->data);
-        curr = g_list_next(curr);
+    if (tag_to_win_cb_hash) {
+        GList *tags = g_hash_table_get_keys(tag_to_win_cb_hash);
+        GList *curr = tags;
+        while (curr) {
+            wins_close_plugin(curr->data);
+            curr = g_list_next(curr);
+        }
+        g_list_free(tags);
     }
-    g_list_free(tags);
 
     g_hash_table_remove(p_window_callbacks, plugin_name);
 }
diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c
index aafa616d..0a350335 100644
--- a/src/plugins/python_api.c
+++ b/src/plugins/python_api.c
@@ -32,6 +32,8 @@
  *
  */
 
+#include "config.h"
+
 #include <Python.h>
 #include <frameobject.h>
 
@@ -54,18 +56,20 @@ python_api_cons_alert(PyObject *self, PyObject *args)
     disable_python_threads();
 
     return Py_BuildValue("");
-
 }
 
 static PyObject*
 python_api_cons_show(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "s", &message)) {
+    PyObject* message = NULL;
+    if (!PyArg_ParseTuple(args, "O", &message)) {
         return Py_BuildValue("");
     }
+
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_cons_show(message);
+    api_cons_show(message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -74,15 +78,21 @@ python_api_cons_show(PyObject *self, PyObject *args)
 static PyObject*
 python_api_cons_show_themed(PyObject *self, PyObject *args)
 {
-    const char *group = NULL;
-    const char *key = NULL;
-    const char *def = NULL;
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "zzzs", &group, &key, &def, &message)) {
+    PyObject *group = NULL;
+    PyObject *key = NULL;
+    PyObject *def = NULL;
+    PyObject *message = NULL;
+    if (!PyArg_ParseTuple(args, "OOOO", &group, &key, &def, &message)) {
         return Py_BuildValue("");
     }
+
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+    char *def_str = python_str_or_unicode_to_string(def);
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_cons_show_themed(group, key, def, message);
+    api_cons_show_themed(group_str, key_str, def_str, message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -91,12 +101,15 @@ python_api_cons_show_themed(PyObject *self, PyObject *args)
 static PyObject*
 python_api_cons_bad_cmd_usage(PyObject *self, PyObject *args)
 {
-    const char *cmd = NULL;
-    if (!PyArg_ParseTuple(args, "s", &cmd)) {
+    PyObject *cmd = NULL;
+    if (!PyArg_ParseTuple(args, "O", &cmd)) {
         return Py_BuildValue("");
     }
+
+    char *cmd_str = python_str_or_unicode_to_string(cmd);
+
     allow_python_threads();
-    api_cons_bad_cmd_usage(cmd);
+    api_cons_bad_cmd_usage(cmd_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -105,22 +118,25 @@ python_api_cons_bad_cmd_usage(PyObject *self, PyObject *args)
 static PyObject*
 python_api_register_command(PyObject *self, PyObject *args)
 {
-    const char *command_name = NULL;
+    PyObject *command_name = NULL;
     int min_args = 0;
     int max_args = 0;
     PyObject *synopsis = NULL;
-    const char *description = NULL;
+    PyObject *description = NULL;
     PyObject *arguments = NULL;
     PyObject *examples = NULL;
     PyObject *p_callback = NULL;
 
-    if (!PyArg_ParseTuple(args, "siiOsOOO", &command_name, &min_args, &max_args,
+    if (!PyArg_ParseTuple(args, "OiiOOOOO", &command_name, &min_args, &max_args,
             &synopsis, &description, &arguments, &examples, &p_callback)) {
         return Py_BuildValue("");
     }
 
+    char *command_name_str = python_str_or_unicode_to_string(command_name);
+    char *description_str = python_str_or_unicode_to_string(description);
+
     char *plugin_name = _python_plugin_name();
-    log_debug("Register command %s for %s", command_name, plugin_name);
+    log_debug("Register command %s for %s", command_name_str, plugin_name);
 
     if (p_callback && PyCallable_Check(p_callback)) {
         Py_ssize_t len = PyList_Size(synopsis);
@@ -128,7 +144,7 @@ python_api_register_command(PyObject *self, PyObject *args)
         Py_ssize_t i = 0;
         for (i = 0; i < len; i++) {
             PyObject *item = PyList_GetItem(synopsis, i);
-            char *c_item = PyString_AsString(item);
+            char *c_item = python_str_or_unicode_to_string(item);
             c_synopsis[i] = c_item;
         }
         c_synopsis[len] = NULL;
@@ -143,11 +159,11 @@ python_api_register_command(PyObject *self, PyObject *args)
                 return Py_BuildValue("");
             }
             PyObject *arg = PyList_GetItem(item, 0);
-            char *c_arg = PyString_AsString(arg);
-            PyObject *desc = PyList_GetItem(item, 1);
-            char *c_desc = PyString_AsString(desc);
-
+            char *c_arg = python_str_or_unicode_to_string(arg);
             c_arguments[i][0] = c_arg;
+
+            PyObject *desc = PyList_GetItem(item, 1);
+            char *c_desc = python_str_or_unicode_to_string(desc);
             c_arguments[i][1] = c_desc;
         }
 
@@ -159,14 +175,14 @@ python_api_register_command(PyObject *self, PyObject *args)
         i = 0;
         for (i = 0; i < len; i++) {
             PyObject *item = PyList_GetItem(examples, i);
-            char *c_item = PyString_AsString(item);
+            char *c_item = python_str_or_unicode_to_string(item);
             c_examples[i] = c_item;
         }
         c_examples[len] = NULL;
 
         allow_python_threads();
-        api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis,
-            description, c_arguments, c_examples, p_callback, python_command_callback, NULL);
+        api_register_command(plugin_name, command_name_str, min_args, max_args, c_synopsis,
+            description_str, c_arguments, c_examples, p_callback, python_command_callback, NULL);
         disable_python_threads();
     }
 
@@ -202,15 +218,17 @@ python_api_register_timed(PyObject *self, PyObject *args)
 static PyObject *
 python_api_completer_add(PyObject *self, PyObject *args)
 {
-    const char *key = NULL;
+    PyObject *key = NULL;
     PyObject *items = NULL;
 
-    if (!PyArg_ParseTuple(args, "sO", &key, &items)) {
+    if (!PyArg_ParseTuple(args, "OO", &key, &items)) {
         return Py_BuildValue("");
     }
 
+    char *key_str = python_str_or_unicode_to_string(key);
+
     char *plugin_name = _python_plugin_name();
-    log_debug("Autocomplete add %s for %s", key, plugin_name);
+    log_debug("Autocomplete add %s for %s", key_str, plugin_name);
 
     Py_ssize_t len = PyList_Size(items);
     char *c_items[len];
@@ -218,13 +236,13 @@ python_api_completer_add(PyObject *self, PyObject *args)
     Py_ssize_t i = 0;
     for (i = 0; i < len; i++) {
         PyObject *item = PyList_GetItem(items, i);
-        char *c_item = PyString_AsString(item);
+        char *c_item = python_str_or_unicode_to_string(item);
         c_items[i] = c_item;
     }
     c_items[len] = NULL;
 
     allow_python_threads();
-    api_completer_add(plugin_name, key, c_items);
+    api_completer_add(plugin_name, key_str, c_items);
     disable_python_threads();
 
     free(plugin_name);
@@ -235,15 +253,17 @@ python_api_completer_add(PyObject *self, PyObject *args)
 static PyObject *
 python_api_completer_remove(PyObject *self, PyObject *args)
 {
-    const char *key = NULL;
+    PyObject *key = NULL;
     PyObject *items = NULL;
 
-    if (!PyArg_ParseTuple(args, "sO", &key, &items)) {
+    if (!PyArg_ParseTuple(args, "OO", &key, &items)) {
         return Py_BuildValue("");
     }
 
+    char *key_str = python_str_or_unicode_to_string(key);
+
     char *plugin_name = _python_plugin_name();
-    log_debug("Autocomplete remove %s for %s", key, plugin_name);
+    log_debug("Autocomplete remove %s for %s", key_str, plugin_name);
 
     Py_ssize_t len = PyList_Size(items);
     char *c_items[len];
@@ -251,13 +271,13 @@ python_api_completer_remove(PyObject *self, PyObject *args)
     Py_ssize_t i = 0;
     for (i = 0; i < len; i++) {
         PyObject *item = PyList_GetItem(items, i);
-        char *c_item = PyString_AsString(item);
+        char *c_item = python_str_or_unicode_to_string(item);
         c_items[i] = c_item;
     }
     c_items[len] = NULL;
 
     allow_python_threads();
-    api_completer_remove(plugin_name, key, c_items);
+    api_completer_remove(plugin_name, key_str, c_items);
     disable_python_threads();
 
     free(plugin_name);
@@ -268,17 +288,19 @@ python_api_completer_remove(PyObject *self, PyObject *args)
 static PyObject *
 python_api_completer_clear(PyObject *self, PyObject *args)
 {
-    const char *key = NULL;
+    PyObject *key = NULL;
 
-    if (!PyArg_ParseTuple(args, "s", &key)) {
+    if (!PyArg_ParseTuple(args, "O", &key)) {
         return Py_BuildValue("");
     }
 
+    char *key_str = python_str_or_unicode_to_string(key);
+
     char *plugin_name = _python_plugin_name();
-    log_debug("Autocomplete clear %s for %s", key, plugin_name);
+    log_debug("Autocomplete clear %s for %s", key_str, plugin_name);
 
     allow_python_threads();
-    api_completer_clear(plugin_name, key);
+    api_completer_clear(plugin_name, key_str);
     disable_python_threads();
 
     free(plugin_name);
@@ -289,16 +311,19 @@ python_api_completer_clear(PyObject *self, PyObject *args)
 static PyObject*
 python_api_notify(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    const char *category = NULL;
+    PyObject *message = NULL;
+    PyObject *category = NULL;
     int timeout_ms = 5000;
 
-    if (!PyArg_ParseTuple(args, "sis", &message, &timeout_ms, &category)) {
+    if (!PyArg_ParseTuple(args, "OiO", &message, &timeout_ms, &category)) {
         return Py_BuildValue("");
     }
 
+    char *message_str = python_str_or_unicode_to_string(message);
+    char *category_str = python_str_or_unicode_to_string(category);
+
     allow_python_threads();
-    api_notify(message, category, timeout_ms);
+    api_notify(message_str, category_str, timeout_ms);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -307,13 +332,15 @@ python_api_notify(PyObject *self, PyObject *args)
 static PyObject*
 python_api_send_line(PyObject *self, PyObject *args)
 {
-    char *line = NULL;
-    if (!PyArg_ParseTuple(args, "s", &line)) {
+    PyObject *line = NULL;
+    if (!PyArg_ParseTuple(args, "O", &line)) {
         return Py_BuildValue("");
     }
 
+    char *line_str = python_str_or_unicode_to_string(line);
+
     allow_python_threads();
-    api_send_line(line);
+    api_send_line(line_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -393,12 +420,15 @@ python_api_current_win_is_console(PyObject *self, PyObject *args)
 static PyObject *
 python_api_log_debug(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "s", &message)) {
+    PyObject *message = NULL;
+    if (!PyArg_ParseTuple(args, "O", &message)) {
         return Py_BuildValue("");
     }
+
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_log_debug(message);
+    api_log_debug(message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -407,13 +437,15 @@ python_api_log_debug(PyObject *self, PyObject *args)
 static PyObject *
 python_api_log_info(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "s", &message)) {
+    PyObject *message = NULL;
+    if (!PyArg_ParseTuple(args, "O", &message)) {
         return Py_BuildValue("");
     }
 
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_log_info(message);
+    api_log_info(message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -422,26 +454,32 @@ python_api_log_info(PyObject *self, PyObject *args)
 static PyObject *
 python_api_log_warning(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "s", &message)) {
+    PyObject *message = NULL;
+    if (!PyArg_ParseTuple(args, "O", &message)) {
         return Py_BuildValue("");
     }
 
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_log_warning(message);
+    api_log_warning(message_str);
     disable_python_threads();
+
     return Py_BuildValue("");
 }
 
 static PyObject *
 python_api_log_error(PyObject *self, PyObject *args)
 {
-    const char *message = NULL;
-    if (!PyArg_ParseTuple(args, "s", &message)) {
+    PyObject *message = NULL;
+    if (!PyArg_ParseTuple(args, "O", &message)) {
         return Py_BuildValue("");
     }
+
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_log_error(message);
+    api_log_error(message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -450,13 +488,15 @@ python_api_log_error(PyObject *self, PyObject *args)
 static PyObject *
 python_api_win_exists(PyObject *self, PyObject *args)
 {
-    char *tag = NULL;
-    if (!PyArg_ParseTuple(args, "s", &tag)) {
+    PyObject *tag = NULL;
+    if (!PyArg_ParseTuple(args, "O", &tag)) {
         return Py_BuildValue("");
     }
 
+    char *tag_str = python_str_or_unicode_to_string(tag);
+
     allow_python_threads();
-    gboolean exists = api_win_exists(tag);
+    gboolean exists = api_win_exists(tag_str);
     disable_python_threads();
 
     if (exists) {
@@ -469,19 +509,21 @@ python_api_win_exists(PyObject *self, PyObject *args)
 static PyObject *
 python_api_win_create(PyObject *self, PyObject *args)
 {
-    char *tag = NULL;
+    PyObject *tag = NULL;
     PyObject *p_callback = NULL;
 
-    if (!PyArg_ParseTuple(args, "sO", &tag, &p_callback)) {
+    if (!PyArg_ParseTuple(args, "OO", &tag, &p_callback)) {
         return Py_BuildValue("");
     }
 
+    char *tag_str = python_str_or_unicode_to_string(tag);
+
     char *plugin_name = _python_plugin_name();
-    log_debug("Win create %s for %s", tag, plugin_name);
+    log_debug("Win create %s for %s", tag_str, plugin_name);
 
     if (p_callback && PyCallable_Check(p_callback)) {
         allow_python_threads();
-        api_win_create(plugin_name, tag, p_callback, python_window_callback, NULL);
+        api_win_create(plugin_name, tag_str, p_callback, python_window_callback, NULL);
         disable_python_threads();
     }
 
@@ -493,14 +535,16 @@ python_api_win_create(PyObject *self, PyObject *args)
 static PyObject *
 python_api_win_focus(PyObject *self, PyObject *args)
 {
-    char *tag = NULL;
+    PyObject *tag = NULL;
 
-    if (!PyArg_ParseTuple(args, "s", &tag)) {
+    if (!PyArg_ParseTuple(args, "O", &tag)) {
         return Py_BuildValue("");
     }
 
+    char *tag_str = python_str_or_unicode_to_string(tag);
+
     allow_python_threads();
-    api_win_focus(tag);
+    api_win_focus(tag_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -509,15 +553,18 @@ python_api_win_focus(PyObject *self, PyObject *args)
 static PyObject *
 python_api_win_show(PyObject *self, PyObject *args)
 {
-    char *tag = NULL;
-    char *line = NULL;
+    PyObject *tag = NULL;
+    PyObject *line = NULL;
 
-    if (!PyArg_ParseTuple(args, "ss", &tag, &line)) {
+    if (!PyArg_ParseTuple(args, "OO", &tag, &line)) {
         return Py_BuildValue("");
     }
 
+    char *tag_str = python_str_or_unicode_to_string(tag);
+    char *line_str = python_str_or_unicode_to_string(line);
+
     allow_python_threads();
-    api_win_show(tag, line);
+    api_win_show(tag_str, line_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -526,18 +573,25 @@ python_api_win_show(PyObject *self, PyObject *args)
 static PyObject *
 python_api_win_show_themed(PyObject *self, PyObject *args)
 {
-    char *tag = NULL;
-    char *group = NULL;
-    char *key = NULL;
-    char *def = NULL;
-    char *line = NULL;
+    PyObject *tag = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
+    PyObject *def = NULL;
+    PyObject *line = NULL;
 
-    if (!PyArg_ParseTuple(args, "szzzs", &tag, &group, &key, &def, &line)) {
+    if (!PyArg_ParseTuple(args, "OOOOO", &tag, &group, &key, &def, &line)) {
+        python_check_error();
         return Py_BuildValue("");
     }
 
+    char *tag_str = python_str_or_unicode_to_string(tag);
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+    char *def_str = python_str_or_unicode_to_string(def);
+    char *line_str = python_str_or_unicode_to_string(line);
+
     allow_python_threads();
-    api_win_show_themed(tag, group, key, def, line);
+    api_win_show_themed(tag_str, group_str, key_str, def_str, line_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -546,13 +600,15 @@ python_api_win_show_themed(PyObject *self, PyObject *args)
 static PyObject*
 python_api_send_stanza(PyObject *self, PyObject *args)
 {
-    const char *stanza = NULL;
-    if (!PyArg_ParseTuple(args, "s", &stanza)) {
+    PyObject *stanza = NULL;
+    if (!PyArg_ParseTuple(args, "O", &stanza)) {
         return Py_BuildValue("O", Py_False);
     }
 
+    char *stanza_str = python_str_or_unicode_to_string(stanza);
+
     allow_python_threads();
-    int res = api_send_stanza(stanza);
+    int res = api_send_stanza(stanza_str);
     disable_python_threads();
     if (res) {
         return Py_BuildValue("O", Py_True);
@@ -564,18 +620,20 @@ python_api_send_stanza(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_get_boolean(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
     PyObject *defobj = NULL;
 
-    if (!PyArg_ParseTuple(args, "ssO!", &group, &key, &PyBool_Type, &defobj)) {
+    if (!PyArg_ParseTuple(args, "OOO!", &group, &key, &PyBool_Type, &defobj)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
     int def = PyObject_IsTrue(defobj);
 
     allow_python_threads();
-    int res = api_settings_get_boolean(group, key, def);
+    int res = api_settings_get_boolean(group_str, key_str, def);
     disable_python_threads();
 
     if (res) {
@@ -588,18 +646,20 @@ python_api_settings_get_boolean(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_set_boolean(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
     PyObject *valobj = NULL;
 
-    if (!PyArg_ParseTuple(args, "ssO!", &group, &key, &PyBool_Type, &valobj)) {
+    if (!PyArg_ParseTuple(args, "OOO!", &group, &key, &PyBool_Type, &valobj)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
     int val = PyObject_IsTrue(valobj);
 
     allow_python_threads();
-    api_settings_set_boolean(group, key, val);
+    api_settings_set_boolean(group_str, key_str, val);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -608,16 +668,20 @@ python_api_settings_set_boolean(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_get_string(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
-    char *def = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
+    PyObject *def = NULL;
 
-    if (!PyArg_ParseTuple(args, "ssz", &group, &key, &def)) {
+    if (!PyArg_ParseTuple(args, "OOO", &group, &key, &def)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+    char *def_str = python_str_or_unicode_to_string(def);
+
     allow_python_threads();
-    char *res = api_settings_get_string(group, key, def);
+    char *res = api_settings_get_string(group_str, key_str, def_str);
     disable_python_threads();
 
     if (res) {
@@ -630,16 +694,20 @@ python_api_settings_get_string(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_set_string(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
-    char *val = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
+    PyObject *val = NULL;
 
-    if (!PyArg_ParseTuple(args, "sss", &group, &key, &val)) {
+    if (!PyArg_ParseTuple(args, "OOO", &group, &key, &val)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+    char *val_str = python_str_or_unicode_to_string(val);
+
     allow_python_threads();
-    api_settings_set_string(group, key, val);
+    api_settings_set_string(group_str, key_str, val_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -648,16 +716,19 @@ python_api_settings_set_string(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_get_int(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
     int def = 0;
 
-    if (!PyArg_ParseTuple(args, "ssi", &group, &key, &def)) {
+    if (!PyArg_ParseTuple(args, "OOi", &group, &key, &def)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+
     allow_python_threads();
-    int res = api_settings_get_int(group, key, def);
+    int res = api_settings_get_int(group_str, key_str, def);
     disable_python_threads();
 
     return Py_BuildValue("i", res);
@@ -666,16 +737,19 @@ python_api_settings_get_int(PyObject *self, PyObject *args)
 static PyObject*
 python_api_settings_set_int(PyObject *self, PyObject *args)
 {
-    char *group = NULL;
-    char *key = NULL;
+    PyObject *group = NULL;
+    PyObject *key = NULL;
     int val = 0;
 
-    if (!PyArg_ParseTuple(args, "ssi", &group, &key, &val)) {
+    if (!PyArg_ParseTuple(args, "OOi", &group, &key, &val)) {
         return Py_BuildValue("");
     }
 
+    char *group_str = python_str_or_unicode_to_string(group);
+    char *key_str = python_str_or_unicode_to_string(key);
+
     allow_python_threads();
-    api_settings_set_int(group, key, val);
+    api_settings_set_int(group_str, key_str, val);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -684,16 +758,20 @@ python_api_settings_set_int(PyObject *self, PyObject *args)
 static PyObject*
 python_api_incoming_message(PyObject *self, PyObject *args)
 {
-    char *barejid = NULL;
-    char *resource = NULL;
-    char *message = NULL;
+    PyObject *barejid = NULL;
+    PyObject *resource = NULL;
+    PyObject *message = NULL;
 
-    if (!PyArg_ParseTuple(args, "sss", &barejid, &resource, &message)) {
+    if (!PyArg_ParseTuple(args, "OOO", &barejid, &resource, &message)) {
         return Py_BuildValue("");
     }
 
+    char *barejid_str = python_str_or_unicode_to_string(barejid);
+    char *resource_str = python_str_or_unicode_to_string(resource);
+    char *message_str = python_str_or_unicode_to_string(message);
+
     allow_python_threads();
-    api_incoming_message(barejid, resource, message);
+    api_incoming_message(barejid_str, resource_str, message_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -702,13 +780,15 @@ python_api_incoming_message(PyObject *self, PyObject *args)
 static PyObject*
 python_api_disco_add_feature(PyObject *self, PyObject *args)
 {
-    char *feature = NULL;
-    if (!PyArg_ParseTuple(args, "s", &feature)) {
+    PyObject *feature = NULL;
+    if (!PyArg_ParseTuple(args, "O", &feature)) {
         return Py_BuildValue("");
     }
 
+    char *feature_str = python_str_or_unicode_to_string(feature);
+
     allow_python_threads();
-    api_disco_add_feature(feature);
+    api_disco_add_feature(feature_str);
     disable_python_threads();
 
     return Py_BuildValue("");
@@ -819,10 +899,45 @@ static PyMethodDef apiMethods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-void
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef profModule =
+{
+    PyModuleDef_HEAD_INIT,
+    "prof",
+    "",
+    -1,
+    apiMethods
+};
+#endif
+
+PyMODINIT_FUNC
 python_api_init(void)
 {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *result = PyModule_Create(&profModule);
+    if (!result) {
+        log_debug("Failed to initialise prof module");
+    } else {
+        log_debug("Initialised prof module");
+    }
+    return result;
+#else
     Py_InitModule("prof", apiMethods);
+#endif
+}
+
+void
+python_init_prof(void)
+{
+#if PY_MAJOR_VERSION >= 3
+    PyImport_AppendInittab("prof", python_api_init);
+    Py_Initialize();
+    PyEval_InitThreads();
+#else
+    Py_Initialize();
+    PyEval_InitThreads();
+    python_api_init();
+#endif
 }
 
 static char*
@@ -830,10 +945,36 @@ _python_plugin_name(void)
 {
     PyThreadState *ts = PyThreadState_Get();
     PyFrameObject *frame = ts->frame;
-    char const* filename = PyString_AsString(frame->f_code->co_filename);
+    char const* filename = python_str_or_unicode_to_string(frame->f_code->co_filename);
     gchar **split = g_strsplit(filename, "/", 0);
     char *plugin_name = strdup(split[g_strv_length(split)-1]);
     g_strfreev(split);
 
     return plugin_name;
 }
+
+char*
+python_str_or_unicode_to_string(void *obj)
+{
+    if (!obj) {
+        return NULL;
+    }
+    PyObject *pyobj = (PyObject*)obj;
+    if (pyobj == Py_None) {
+        return NULL;
+    }
+
+#if PY_MAJOR_VERSION >= 3
+    if (PyUnicode_Check(pyobj)) {
+        return strdup(PyBytes_AS_STRING(PyUnicode_AsUTF8String(pyobj)));
+    } else {
+        return strdup(PyBytes_AS_STRING(pyobj));
+    }
+#else
+    if (PyUnicode_Check(pyobj)) {
+        return strdup(PyString_AsString(PyUnicode_AsUTF8String(pyobj)));
+    } else {
+        return strdup(PyString_AsString(pyobj));
+    }
+#endif
+}
diff --git a/src/plugins/python_api.h b/src/plugins/python_api.h
index 01f695c9..27c17a3d 100644
--- a/src/plugins/python_api.h
+++ b/src/plugins/python_api.h
@@ -36,11 +36,13 @@
 #define PYTHON_API_H
 
 void python_env_init(void);
-void python_api_init(void);
+void python_init_prof(void);
 void python_shutdown(void);
 
 void python_command_callback(PluginCommand *command, gchar **args);
 void python_timed_callback(PluginTimedFunction *timed_function);
 void python_window_callback(PluginWindowCallback *window_callback, char *tag, char *line);
 
+char* python_str_or_unicode_to_string(void *obj);
+
 #endif
diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c
index 1859ac17..61c7573f 100644
--- a/src/plugins/python_plugins.c
+++ b/src/plugins/python_plugins.c
@@ -34,6 +34,8 @@
 
 #include <Python.h>
 
+#include "config.h"
+
 #include "config/preferences.h"
 #include "plugins/api.h"
 #include "plugins/callbacks.h"
@@ -68,20 +70,23 @@ python_env_init(void)
 {
     loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_unref_module);
 
-    Py_Initialize();
-    PyEval_InitThreads();
-    python_api_init();
+    python_init_prof();
+
+    const char *ver = Py_GetVersion();
+    cons_show("PYTHON: %s", ver);
 
+    gchar *plugins_dir = plugins_get_dir();
     GString *path = g_string_new("import sys\n");
     g_string_append(path, "sys.path.append(\"");
-    gchar *plugins_dir = plugins_get_dir();
     g_string_append(path, plugins_dir);
-    g_free(plugins_dir);
     g_string_append(path, "/\")\n");
 
     PyRun_SimpleString(path->str);
+    python_check_error();
 
     g_string_free(path, TRUE);
+    g_free(plugins_dir);
+
     allow_python_threads();
 }
 
@@ -96,7 +101,9 @@ python_plugin_create(const char *const filename)
     } else {
         gchar *module_name = g_strndup(filename, strlen(filename) - 3);
         p_module = PyImport_ImportModule(module_name);
-        g_hash_table_insert(loaded_modules, strdup(filename), p_module);
+        if (p_module) {
+            g_hash_table_insert(loaded_modules, strdup(filename), p_module);
+        }
         g_free(module_name);
     }
 
@@ -277,20 +284,10 @@ python_pre_chat_message_display_hook(ProfPlugin *plugin, const char *const jid,
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -334,20 +331,10 @@ python_pre_chat_message_send_hook(ProfPlugin *plugin, const char * const jid, co
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -391,20 +378,10 @@ python_pre_room_message_display_hook(ProfPlugin *plugin, const char * const room
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -449,20 +426,10 @@ python_pre_room_message_send_hook(ProfPlugin *plugin, const char *const room, co
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -529,20 +496,10 @@ python_pre_priv_message_display_hook(ProfPlugin *plugin, const char *const room,
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -588,20 +545,10 @@ python_pre_priv_message_send_hook(ProfPlugin *plugin, const char *const room, co
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -646,20 +593,10 @@ python_on_message_stanza_send_hook(ProfPlugin *plugin, const char *const text)
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -711,20 +648,10 @@ python_on_presence_stanza_send_hook(ProfPlugin *plugin, const char *const text)
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -776,20 +703,10 @@ python_on_iq_stanza_send_hook(ProfPlugin *plugin, const char *const text)
             PyObject *result = PyObject_CallObject(p_function, p_args);
             python_check_error();
             Py_XDECREF(p_function);
-            if (PyUnicode_Check(result)) {
-                char *result_str = strdup(PyString_AsString(PyUnicode_AsUTF8String(result)));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else if (result != Py_None) {
-                char *result_str = strdup(PyString_AsString(result));
-                Py_XDECREF(result);
-                allow_python_threads();
-                return result_str;
-            } else {
-                allow_python_threads();
-                return NULL;
-            }
+            char *result_str = python_str_or_unicode_to_string(result);
+            allow_python_threads();
+
+            return result_str;
         }
     }
 
@@ -917,6 +834,7 @@ python_check_error(void)
 {
     if (PyErr_Occurred()) {
         PyErr_Print();
+        PyRun_SimpleString("import sys\nsys.stdout.flush()");
         PyErr_Clear();
     }
 }