summaryrefslogtreecommitdiffstats
path: root/plugins/python/python.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/python/python.c')
-rw-r--r--plugins/python/python.c2834
1 files changed, 0 insertions, 2834 deletions
diff --git a/plugins/python/python.c b/plugins/python/python.c
deleted file mode 100644
index 4403474d..00000000
--- a/plugins/python/python.c
+++ /dev/null
@@ -1,2834 +0,0 @@
-/*
-* Copyright (c) 2002-2003 Gustavo Niemeyer <niemeyer@conectiva.com>
-*
-* XChat Python Plugin Interface
-*
-* Xchat Python Plugin Interface is free software; you can redistribute
-* it and/or modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2 of the
-* License, or (at your option) any later version.
-*
-* pybot is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this file; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
-*/
-
-/* Thread support
- * ==============
- *
- * The python interpreter has a global interpreter lock. Any thread
- * executing must acquire it before working with data accessible from
- * python code. Here we must also care about xchat not being
- * thread-safe. We do this by using an xchat lock, which protects
- * xchat instructions from being executed out of time (when this
- * plugin is not "active").
- *
- * When xchat calls python code:
- * - Change the current_plugin for the executing plugin;
- * - Release xchat lock
- * - Acquire the global interpreter lock
- * - Make the python call
- * - Release the global interpreter lock
- * - Acquire xchat lock
- *
- * When python code calls xchat:
- * - Release the global interpreter lock
- * - Acquire xchat lock
- * - Restore context, if necessary
- * - Make the xchat call
- * - Release xchat lock
- * - Acquire the global interpreter lock
- *
- * Inside a timer, so that individual threads have a chance to run:
- * - Release xchat lock
- * - Go ahead threads. Have a nice time!
- * - Acquire xchat lock
- *
- */
-
-#include "config.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#ifdef WIN32
-#include <direct.h>
-#else
-#include <unistd.h>
-#include <dirent.h>
-#endif
-
-#include "hexchat-plugin.h"
-#undef _POSIX_C_SOURCE /* Avoid warnings from /usr/include/features.h */
-#undef _XOPEN_SOURCE
-#undef HAVE_MEMRCHR /* Avoid redefinition in Python.h */
-#undef HAVE_STRINGS_H
-#include <Python.h>
-#include <structmember.h>
-#include <pythread.h>
-
-/* Macros to convert version macros into string literals.
- * The indirect macro is a well-known preprocessor trick to force X to be evaluated before the # operator acts to make it a string literal.
- * If STRINGIZE were to be directly defined as #X instead, VERSION would be "VERSION_MAJOR" instead of "1".
- */
-#define STRINGIZE2(X) #X
-#define STRINGIZE(X) STRINGIZE2(X)
-
-/* Version number macros */
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 0
-
-/* Version string macro e.g 1.0/3.3 */
-#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "/" \
- STRINGIZE(PY_MAJOR_VERSION) "." STRINGIZE (PY_MINOR_VERSION)
-
-/* #define's for Python 2 */
-#if PY_MAJOR_VERSION == 2
-#undef PyLong_Check
-#define PyLong_Check PyInt_Check
-#define PyLong_AsLong PyInt_AsLong
-#define PyLong_FromLong PyInt_FromLong
-
-#undef PyUnicode_Check
-#undef PyUnicode_FromString
-#undef PyUnicode_FromFormat
-#define PyUnicode_Check PyString_Check
-#define PyUnicode_AsFormat PyString_AsFormat
-#define PyUnicode_FromFormat PyString_FromFormat
-#define PyUnicode_FromString PyString_FromString
-#define PyUnicode_AsUTF8 PyString_AsString
-
-#ifdef WIN32
-#undef WITH_THREAD
-#endif
-#endif
-
-/* #define for Python 3 */
-#if PY_MAJOR_VERSION == 3
-#define IS_PY3K
-#endif
-
-#define NONE 0
-#define ALLOW_THREADS 1
-#define RESTORE_CONTEXT 2
-
-#ifdef WITH_THREAD
-#define ACQUIRE_XCHAT_LOCK() PyThread_acquire_lock(xchat_lock, 1)
-#define RELEASE_XCHAT_LOCK() PyThread_release_lock(xchat_lock)
-#define BEGIN_XCHAT_CALLS(x) \
- do { \
- PyObject *calls_plugin = NULL; \
- PyThreadState *calls_thread; \
- if ((x) & RESTORE_CONTEXT) \
- calls_plugin = Plugin_GetCurrent(); \
- calls_thread = PyEval_SaveThread(); \
- ACQUIRE_XCHAT_LOCK(); \
- if (!((x) & ALLOW_THREADS)) { \
- PyEval_RestoreThread(calls_thread); \
- calls_thread = NULL; \
- } \
- if (calls_plugin) \
- hexchat_set_context(ph, \
- Plugin_GetContext(calls_plugin)); \
- while (0)
-#define END_XCHAT_CALLS() \
- RELEASE_XCHAT_LOCK(); \
- if (calls_thread) \
- PyEval_RestoreThread(calls_thread); \
- } while(0)
-#else
-#define ACQUIRE_XCHAT_LOCK()
-#define RELEASE_XCHAT_LOCK()
-#define BEGIN_XCHAT_CALLS(x)
-#define END_XCHAT_CALLS()
-#endif
-
-#ifdef WITH_THREAD
-
-#define BEGIN_PLUGIN(plg) \
- do { \
- hexchat_context *begin_plugin_ctx = hexchat_get_context(ph); \
- RELEASE_XCHAT_LOCK(); \
- Plugin_AcquireThread(plg); \
- Plugin_SetContext(plg, begin_plugin_ctx); \
- } while (0)
-#define END_PLUGIN(plg) \
- do { \
- Plugin_ReleaseThread(plg); \
- ACQUIRE_XCHAT_LOCK(); \
- } while (0)
-
-#else /* !WITH_THREAD (win32) */
-
-static PyThreadState *pTempThread;
-
-#define BEGIN_PLUGIN(plg) \
- do { \
- hexchat_context *begin_plugin_ctx = hexchat_get_context(ph); \
- RELEASE_XCHAT_LOCK(); \
- PyEval_AcquireLock(); \
- pTempThread = PyThreadState_Swap(((PluginObject *)(plg))->tstate); \
- Plugin_SetContext(plg, begin_plugin_ctx); \
- } while (0)
-#define END_PLUGIN(plg) \
- do { \
- ((PluginObject *)(plg))->tstate = PyThreadState_Swap(pTempThread); \
- PyEval_ReleaseLock(); \
- ACQUIRE_XCHAT_LOCK(); \
- } while (0)
-
-#endif /* !WITH_THREAD */
-
-#define Plugin_Swap(x) \
- PyThreadState_Swap(((PluginObject *)(x))->tstate)
-#define Plugin_AcquireThread(x) \
- PyEval_AcquireThread(((PluginObject *)(x))->tstate)
-#define Plugin_ReleaseThread(x) \
- Util_ReleaseThread(((PluginObject *)(x))->tstate)
-#define Plugin_GetFilename(x) \
- (((PluginObject *)(x))->filename)
-#define Plugin_GetName(x) \
- (((PluginObject *)(x))->name)
-#define Plugin_GetVersion(x) \
- (((PluginObject *)(x))->version)
-#define Plugin_GetDesc(x) \
- (((PluginObject *)(x))->description)
-#define Plugin_GetHooks(x) \
- (((PluginObject *)(x))->hooks)
-#define Plugin_GetContext(x) \
- (((PluginObject *)(x))->context)
-#define Plugin_SetFilename(x, y) \
- ((PluginObject *)(x))->filename = (y);
-#define Plugin_SetName(x, y) \
- ((PluginObject *)(x))->name = (y);
-#define Plugin_SetVersion(x, y) \
- ((PluginObject *)(x))->version = (y);
-#define Plugin_SetDescription(x, y) \
- ((PluginObject *)(x))->description = (y);
-#define Plugin_SetHooks(x, y) \
- ((PluginObject *)(x))->hooks = (y);
-#define Plugin_SetContext(x, y) \
- ((PluginObject *)(x))->context = (y);
-#define Plugin_SetGui(x, y) \
- ((PluginObject *)(x))->gui = (y);
-
-#define HOOK_XCHAT 1
-#define HOOK_XCHAT_ATTR 2
-#define HOOK_UNLOAD 3
-
-/* ===================================================================== */
-/* Object definitions */
-
-typedef struct {
- PyObject_HEAD
- int softspace; /* We need it for print support. */
-} XChatOutObject;
-
-typedef struct {
- PyObject_HEAD
- hexchat_context *context;
-} ContextObject;
-
-typedef struct {
- PyObject_HEAD
- PyObject *time;
-} AttributeObject;
-
-typedef struct {
- PyObject_HEAD
- const char *listname;
- PyObject *dict;
-} ListItemObject;
-
-typedef struct {
- PyObject_HEAD
- char *name;
- char *version;
- char *filename;
- char *description;
- GSList *hooks;
- PyThreadState *tstate;
- hexchat_context *context;
- void *gui;
-} PluginObject;
-
-typedef struct {
- int type;
- PyObject *plugin;
- PyObject *callback;
- PyObject *userdata;
- char *name;
- void *data; /* A handle, when type == HOOK_XCHAT */
-} Hook;
-
-
-/* ===================================================================== */
-/* Function declarations */
-
-static PyObject *Util_BuildList(char *word[]);
-static PyObject *Util_BuildEOLList(char *word[]);
-static void Util_Autoload(void);
-static char *Util_Expand(char *filename);
-
-static int Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata);
-static int Callback_Command(char *word[], char *word_eol[], void *userdata);
-static int Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata);
-static int Callback_Print(char *word[], void *userdata);
-static int Callback_Timer(void *userdata);
-static int Callback_ThreadTimer(void *userdata);
-
-static PyObject *XChatOut_New(void);
-static PyObject *XChatOut_write(PyObject *self, PyObject *args);
-static void XChatOut_dealloc(PyObject *self);
-
-static PyObject *Attribute_New(hexchat_event_attrs *attrs);
-
-static void Context_dealloc(PyObject *self);
-static PyObject *Context_set(ContextObject *self, PyObject *args);
-static PyObject *Context_command(ContextObject *self, PyObject *args);
-static PyObject *Context_prnt(ContextObject *self, PyObject *args);
-static PyObject *Context_get_info(ContextObject *self, PyObject *args);
-static PyObject *Context_get_list(ContextObject *self, PyObject *args);
-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, PyObject *xcoobj);
-static PyObject *Plugin_GetCurrent(void);
-static PluginObject *Plugin_ByString(char *str);
-static Hook *Plugin_AddHook(int type, PyObject *plugin, PyObject *callback,
- PyObject *userdata, char *name, void *data);
-static Hook *Plugin_FindHook(PyObject *plugin, char *name);
-static void Plugin_RemoveHook(PyObject *plugin, Hook *hook);
-static void Plugin_RemoveAllHooks(PyObject *plugin);
-
-static PyObject *Module_hexchat_command(PyObject *self, PyObject *args);
-static PyObject *Module_xchat_prnt(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_get_context(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_find_context(PyObject *self, PyObject *args,
- PyObject *kwargs);
-static PyObject *Module_hexchat_get_info(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_hook_command(PyObject *self, PyObject *args,
- PyObject *kwargs);
-static PyObject *Module_hexchat_hook_server(PyObject *self, PyObject *args,
- PyObject *kwargs);
-static PyObject *Module_hexchat_hook_print(PyObject *self, PyObject *args,
- PyObject *kwargs);
-static PyObject *Module_hexchat_hook_timer(PyObject *self, PyObject *args,
- PyObject *kwargs);
-static PyObject *Module_hexchat_unhook(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_get_info(PyObject *self, PyObject *args);
-static PyObject *Module_xchat_get_list(PyObject *self, PyObject *args);
-static PyObject *Module_xchat_get_lists(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_nickcmp(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_strip(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_pluginpref_set(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_pluginpref_get(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_pluginpref_delete(PyObject *self, PyObject *args);
-static PyObject *Module_hexchat_pluginpref_list(PyObject *self, PyObject *args);
-
-static void IInterp_Exec(char *command);
-static int IInterp_Cmd(char *word[], char *word_eol[], void *userdata);
-
-static void Command_PyList(void);
-static void Command_PyLoad(char *filename);
-static void Command_PyUnload(char *name);
-static void Command_PyReload(char *name);
-static void Command_PyAbout(void);
-static int Command_Py(char *word[], char *word_eol[], void *userdata);
-
-/* ===================================================================== */
-/* Static declarations and definitions */
-
-static PyTypeObject Plugin_Type;
-static PyTypeObject XChatOut_Type;
-static PyTypeObject Context_Type;
-static PyTypeObject ListItem_Type;
-static PyTypeObject Attribute_Type;
-
-static PyThreadState *main_tstate = NULL;
-static void *thread_timer = NULL;
-
-static hexchat_plugin *ph;
-static GSList *plugin_list = NULL;
-
-static PyObject *interp_plugin = NULL;
-static PyObject *xchatout = NULL;
-
-#ifdef WITH_THREAD
-static PyThread_type_lock xchat_lock = NULL;
-#endif
-
-static const char usage[] = "\
-Usage: /PY LOAD <filename>\n\
- UNLOAD <filename|name>\n\
- RELOAD <filename|name>\n\
- LIST\n\
- EXEC <command>\n\
- CONSOLE\n\
- ABOUT\n\
-\n";
-
-static const char about[] = "HexChat Python interface version " VERSION "\n";
-
-/* ===================================================================== */
-/* Utility functions */
-
-static PyObject *
-Util_BuildList(char *word[])
-{
- PyObject *list;
- int listsize = 31;
- int i;
- /* Find the last valid array member; there may be intermediate NULLs that
- * would otherwise cause us to drop some members. */
- while (listsize > 0 &&
- (word[listsize] == NULL || word[listsize][0] == 0))
- listsize--;
- list = PyList_New(listsize);
- if (list == NULL) {
- PyErr_Print();
- return NULL;
- }
- for (i = 1; i <= listsize; i++) {
- PyObject *o;
- if (word[i] == NULL) {
- Py_INCREF(Py_None);
- o = Py_None;
- } else {
- /* This handles word[i][0] == 0 automatically. */
- o = PyUnicode_FromString(word[i]);
- }
- PyList_SetItem(list, i - 1, o);
- }
- return list;
-}
-
-static PyObject *
-Util_BuildEOLList(char *word[])
-{
- PyObject *list;
- int listsize = 31;
- int i;
- char *accum = NULL;
- char *last = NULL;
-
- /* Find the last valid array member; there may be intermediate NULLs that
- * would otherwise cause us to drop some members. */
- while (listsize > 0 &&
- (word[listsize] == NULL || word[listsize][0] == 0))
- listsize--;
- list = PyList_New(listsize);
- if (list == NULL) {
- PyErr_Print();
- return NULL;
- }
- for (i = listsize; i > 0; i--) {
- char *part = word[i];
- PyObject *uni_part;
- if (accum == NULL) {
- accum = g_strdup (part);
- } else if (part != NULL && part[0] != 0) {
- last = accum;
- accum = g_strjoin(" ", part, last, NULL);
- g_free (last);
- last = NULL;
-
- if (accum == NULL) {
- Py_DECREF(list);
- hexchat_print(ph, "Not enough memory to alloc accum"
- "for python plugin callback");
- return NULL;
- }
- }
- uni_part = PyUnicode_FromString(accum);
- PyList_SetItem(list, i - 1, uni_part);
- }
-
- g_free (last);
- g_free (accum);
-
- return list;
-}
-
-static void
-Util_Autoload_from (const char *dir_name)
-{
- gchar *oldcwd;
- const char *entry_name;
- GDir *dir;
-
- oldcwd = g_get_current_dir ();
- if (oldcwd == NULL)
- return;
- if (g_chdir(dir_name) != 0)
- {
- g_free (oldcwd);
- return;
- }
- dir = g_dir_open (".", 0, NULL);
- if (dir == NULL)
- {
- g_free (oldcwd);
- return;
- }
- while ((entry_name = g_dir_read_name (dir)))
- {
- if (g_str_has_suffix (entry_name, ".py"))
- Command_PyLoad((char*)entry_name);
- }
- g_dir_close (dir);
- g_chdir (oldcwd);
-}
-
-static void
-Util_Autoload()
-{
- const char *xdir;
- char *sub_dir;
- /* we need local filesystem encoding for g_chdir, g_dir_open etc */
-
- xdir = hexchat_get_info(ph, "configdir");
-
- /* auto-load from subdirectory addons */
- sub_dir = g_build_filename (xdir, "addons", NULL);
- Util_Autoload_from(sub_dir);
- g_free (sub_dir);
-}
-
-static char *
-Util_Expand(char *filename)
-{
- char *expanded;
-
- /* Check if this is an absolute path. */
- if (g_path_is_absolute(filename)) {
- if (g_file_test(filename, G_FILE_TEST_EXISTS))
- return g_strdup(filename);
- else
- return NULL;
- }
-
- /* Check if it starts with ~/ and expand the home if positive. */
- if (*filename == '~' && *(filename+1) == '/') {
- expanded = g_build_filename(g_get_home_dir(),
- filename+2, NULL);
- if (g_file_test(expanded, G_FILE_TEST_EXISTS))
- return expanded;
- else {
- g_free(expanded);
- return NULL;
- }
- }
-
- /* Check if it's in the current directory. */
- expanded = g_build_filename(g_get_current_dir(),
- filename, NULL);
- if (g_file_test(expanded, G_FILE_TEST_EXISTS))
- return expanded;
- g_free(expanded);
-
- /* Check if ~/.config/hexchat/addons/<filename> exists. */
- expanded = g_build_filename(hexchat_get_info(ph, "configdir"),
- "addons", filename, NULL);
- if (g_file_test(expanded, G_FILE_TEST_EXISTS))
- return expanded;
- g_free(expanded);
-
- return NULL;
-}
-
-/* Similar to PyEval_ReleaseThread, but accepts NULL thread states. */
-static void
-Util_ReleaseThread(PyThreadState *tstate)
-{
- PyThreadState *old_tstate;
- if (tstate == NULL)
- Py_FatalError("PyEval_ReleaseThread: NULL thread state");
- old_tstate = PyThreadState_Swap(NULL);
- if (old_tstate != tstate && old_tstate != NULL)
- Py_FatalError("PyEval_ReleaseThread: wrong thread state");
- PyEval_ReleaseLock();
-}
-
-/* ===================================================================== */
-/* Hookable functions. These are the entry points to python code, besides
- * the load function, and the hooks for interactive interpreter. */
-
-static int
-Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
-{
- Hook *hook = (Hook *) userdata;
- PyObject *retobj;
- PyObject *word_list, *word_eol_list;
- PyObject *attributes;
- int ret = HEXCHAT_EAT_NONE;
- PyObject *plugin;
-
- plugin = hook->plugin;
- BEGIN_PLUGIN(plugin);
-
- word_list = Util_BuildList(word);
- if (word_list == NULL) {
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
- word_eol_list = Util_BuildList(word_eol);
- if (word_eol_list == NULL) {
- Py_DECREF(word_list);
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
-
- attributes = Attribute_New(attrs);
-
- if (hook->type == HOOK_XCHAT_ATTR)
- retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list,
- word_eol_list, hook->userdata, attributes);
- else
- retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
- word_eol_list, hook->userdata);
- Py_DECREF(word_list);
- Py_DECREF(word_eol_list);
- Py_DECREF(attributes);
-
- if (retobj == Py_None) {
- ret = HEXCHAT_EAT_NONE;
- Py_DECREF(retobj);
- } else if (retobj) {
- ret = PyLong_AsLong(retobj);
- Py_DECREF(retobj);
- } else {
- PyErr_Print();
- }
-
- END_PLUGIN(plugin);
-
- return ret;
-}
-
-static int
-Callback_Command(char *word[], char *word_eol[], void *userdata)
-{
- Hook *hook = (Hook *) userdata;
- PyObject *retobj;
- PyObject *word_list, *word_eol_list;
- int ret = HEXCHAT_EAT_NONE;
- PyObject *plugin;
-
- plugin = hook->plugin;
- BEGIN_PLUGIN(plugin);
-
- word_list = Util_BuildList(word);
- if (word_list == NULL) {
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
- word_eol_list = Util_BuildList(word_eol);
- if (word_eol_list == NULL) {
- Py_DECREF(word_list);
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
-
- retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
- word_eol_list, hook->userdata);
- Py_DECREF(word_list);
- Py_DECREF(word_eol_list);
-
- if (retobj == Py_None) {
- ret = HEXCHAT_EAT_NONE;
- Py_DECREF(retobj);
- } else if (retobj) {
- ret = PyLong_AsLong(retobj);
- Py_DECREF(retobj);
- } else {
- PyErr_Print();
- }
-
- END_PLUGIN(plugin);
-
- return ret;
-}
-
-static int
-Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata)
-{
- Hook *hook = (Hook *) userdata;
- PyObject *retobj;
- PyObject *word_list;
- PyObject *word_eol_list;
- PyObject *attributes;
- int ret = HEXCHAT_EAT_NONE;
- PyObject *plugin;
-
- plugin = hook->plugin;
- BEGIN_PLUGIN(plugin);
-
- word_list = Util_BuildList(word);
- if (word_list == NULL) {
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
- word_eol_list = Util_BuildEOLList(word);
- if (word_eol_list == NULL) {
- Py_DECREF(word_list);
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
-
- attributes = Attribute_New(attrs);
-
- retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list,
- word_eol_list, hook->userdata, attributes);
-
- Py_DECREF(word_list);
- Py_DECREF(word_eol_list);
- Py_DECREF(attributes);
-
- if (retobj == Py_None) {
- ret = HEXCHAT_EAT_NONE;
- Py_DECREF(retobj);
- } else if (retobj) {
- ret = PyLong_AsLong(retobj);
- Py_DECREF(retobj);
- } else {
- PyErr_Print();
- }
-
- END_PLUGIN(plugin);
-
- return ret;
-}
-
-static int
-Callback_Print(char *word[], void *userdata)
-{
- Hook *hook = (Hook *) userdata;
- PyObject *retobj;
- PyObject *word_list;
- PyObject *word_eol_list;
- int ret = HEXCHAT_EAT_NONE;
- PyObject *plugin;
-
- plugin = hook->plugin;
- BEGIN_PLUGIN(plugin);
-
- word_list = Util_BuildList(word);
- if (word_list == NULL) {
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
- word_eol_list = Util_BuildEOLList(word);
- if (word_eol_list == NULL) {
- Py_DECREF(word_list);
- END_PLUGIN(plugin);
- return HEXCHAT_EAT_NONE;
- }
-
- retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
- word_eol_list, hook->userdata);
-
- Py_DECREF(word_list);
- Py_DECREF(word_eol_list);
-
- if (retobj == Py_None) {
- ret = HEXCHAT_EAT_NONE;
- Py_DECREF(retobj);
- } else if (retobj) {
- ret = PyLong_AsLong(retobj);
- Py_DECREF(retobj);
- } else {
- PyErr_Print();
- }
-
- END_PLUGIN(plugin);
-
- return ret;
-}
-
-static int
-Callback_Timer(void *userdata)
-{
- Hook *hook = (Hook *) userdata;
- PyObject *retobj;
- int ret = 0;
- PyObject *plugin;
-
- plugin = hook->plugin;
-
- BEGIN_PLUGIN(hook->plugin);
-
- retobj = PyObject_CallFunction(hook->callback, "(O)", hook->userdata);
-
- if (retobj) {
- ret = PyObject_IsTrue(retobj);
- Py_DECREF(retobj);
- } else {
- PyErr_Print();
- }
-
- /* Returning 0 for this callback unhooks itself. */
- if (ret == 0)
- Plugin_RemoveHook(plugin, hook);
-
- END_PLUGIN(plugin);
-
- return ret;
-}
-
-#ifdef WITH_THREAD
-static int
-Callback_ThreadTimer(void *userdata)
-{
- RELEASE_XCHAT_LOCK();
-#ifndef WIN32
- usleep(1);
-#endif
- ACQUIRE_XCHAT_LOCK();
- return 1;
-}
-#endif
-
-/* ===================================================================== */
-/* XChatOut object */
-
-/* We keep this information global, so we can reset it when the
- * deinit function is called. */
-/* XXX This should be somehow bound to the printing context. */
-static GString *xchatout_buffer = NULL;
-
-static PyObject *
-XChatOut_New()
-{
- XChatOutObject *xcoobj;
- xcoobj = PyObject_New(XChatOutObject, &XChatOut_Type);
- if (xcoobj != NULL)
- xcoobj->softspace = 0;
- return (PyObject *) xcoobj;
-}
-
-static void
-XChatOut_dealloc(PyObject *self)
-{
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-/* This is a little bit complex because we have to buffer data
- * until a \n is received, since xchat breaks the line automatically.
- * We also crop the last \n for this reason. */
-static PyObject *
-XChatOut_write(PyObject *self, PyObject *args)
-{
- gboolean add_space;
- char *data, *pos;
-
- if (!PyArg_ParseTuple(args, "s:write", &data))
- return NULL;
- if (!data || !*data) {
- Py_RETURN_NONE;
- }
- BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS);
- if (((XChatOutObject *)self)->softspace) {
- add_space = TRUE;
- ((XChatOutObject *)self)->softspace = 0;
- } else {
- add_space = FALSE;
- }
-
- g_string_append (xchatout_buffer, data);
-
- /* If not end of line add space to continue buffer later */
- if (add_space && xchatout_buffer->str[xchatout_buffer->len - 1] != '\n')
- {
- g_string_append_c (xchatout_buffer, ' ');
- }
-
- /* If there is an end of line print up to that */
- if ((pos = strrchr (xchatout_buffer->str, '\n')))
- {
- *pos = '\0';
- hexchat_print (ph, xchatout_buffer->str);
-
- /* Then remove it from buffer */
- g_string_erase (xchatout_buffer, 0, pos - xchatout_buffer->str + 1);
- }
-
- END_XCHAT_CALLS();
- Py_RETURN_NONE;
-}
-
-#define OFF(x) offsetof(XChatOutObject, x)
-
-static PyMemberDef XChatOut_members[] = {
- {"softspace", T_INT, OFF(softspace), 0},
- {0}
-};
-
-static PyMethodDef XChatOut_methods[] = {
- {"write", XChatOut_write, METH_VARARGS},
- {NULL, NULL}
-};
-
-static PyTypeObject XChatOut_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "hexchat.XChatOut", /*tp_name*/
- sizeof(XChatOutObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- XChatOut_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- XChatOut_methods, /*tp_methods*/
- XChatOut_members, /*tp_members*/
- 0, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- 0, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_GenericNew, /*tp_new*/
- PyObject_Del, /*tp_free*/
- 0, /*tp_is_gc*/
-};
-
-
-/* ===================================================================== */
-/* Attribute object */
-
-#undef OFF
-#define OFF(x) offsetof(AttributeObject, x)
-
-static PyMemberDef Attribute_members[] = {
- {"time", T_OBJECT, OFF(time), 0},
- {0}
-};
-
-static void
-Attribute_dealloc(PyObject *self)
-{
- Py_DECREF(((AttributeObject*)self)->time);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *
-Attribute_repr(PyObject *self)
-{
- return PyUnicode_FromFormat("<Attribute object at %p>", self);
-}
-
-static PyTypeObject Attribute_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "hexchat.Attribute", /*tp_name*/
- sizeof(AttributeObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- Attribute_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- Attribute_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- 0, /*tp_methods*/
- Attribute_members, /*tp_members*/
- 0, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- 0, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_GenericNew, /*tp_new*/
- PyObject_Del, /*tp_free*/
- 0, /*tp_is_gc*/
-};
-
-static PyObject *
-Attribute_New(hexchat_event_attrs *attrs)
-{
- AttributeObject *attr;
- attr = PyObject_New(AttributeObject, &Attribute_Type);
- if (attr != NULL) {
- attr->time = PyLong_FromLong((long)attrs->server_time_utc);
- }
- return (PyObject *) attr;
-}
-
-
-/* ===================================================================== */
-/* Context object */
-
-static void
-Context_dealloc(PyObject *self)
-{
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *
-Context_set(ContextObject *self, PyObject *args)
-{
- PyObject *plugin = Plugin_GetCurrent();
- Plugin_SetContext(plugin, self->context);
- Py_RETURN_NONE;
-}
-
-static PyObject *
-Context_command(ContextObject *self, PyObject *args)
-{
- char *text;
- if (!PyArg_ParseTuple(args, "s:command", &text))
- return NULL;
- BEGIN_XCHAT_CALLS(ALLOW_THREADS);
- hexchat_set_context(ph, self->context);
- hexchat_command(ph, text);
- END_XCHAT_CALLS();
- Py_RETURN_NONE;
-}
-
-static PyObject *
-Context_prnt(ContextObject *self, PyObject *args)
-{
- char *text;
- if (!PyArg_ParseTuple(args, "s:prnt", &text))
- return NULL;
- BEGIN_XCHAT_CALLS(ALLOW_THREADS);
- hexchat_set_context(ph, self->context);
- hexchat_print(ph, text);
- END_XCHAT_CALLS();
- Py_RETURN_NONE;
-}
-
-static PyObject *
-Context_emit_print(ContextObject *self, PyObject *args, PyObject *kwargs)
-{
- char *argv[6];
- char *name;
- int res;
- long time = 0;
- hexchat_event_attrs *attrs;
- char *kwlist[] = {"name", "arg1", "arg2", "arg3",
- "arg4", "arg5", "arg6",
- "time", NULL};
- memset(&argv, 0, sizeof(char*)*6);
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ssssssl:print_event", kwlist, &name,
- &argv[0], &argv[1], &argv[2],
- &argv[3], &argv[4], &argv[5],
- &time))
- return NULL;
- BEGIN_XCHAT_CALLS(ALLOW_THREADS);
- hexchat_set_context(ph, self->context);
- attrs = hexchat_event_attrs_create(ph);
- attrs->server_time_utc = (time_t)time;
-
- res = hexchat_emit_print_attrs(ph, attrs, name, argv[0], argv[1], argv[2],
- argv[3], argv[4], argv[5], NULL);
-
- hexchat_event_attrs_free(ph, attrs);
- END_XCHAT_CALLS();
- return PyLong_FromLong(res);
-}
-
-static PyObject *
-Context_get_info(ContextObject *self, PyObject *args)
-{
- const char *info;
- char *name;
- if (!PyArg_ParseTuple(args, "s:get_info", &name))
- return NULL;
- BEGIN_XCHAT_CALLS(NONE);
- hexchat_set_context(ph, self->context);
- info = hexchat_get_info(ph, name);
- END_XCHAT_CALLS();
- if (info == NULL) {
- Py_RETURN_NONE;
- }
- return PyUnicode_FromString(info);
-}
-
-static PyObject *
-Context_get_list(ContextObject *self, PyObject *args)
-{
- PyObject *plugin = Plugin_GetCurrent();
- hexchat_context *saved_context = Plugin_GetContext(plugin);
- PyObject *ret;
- Plugin_SetContext(plugin, self->context);
- ret = Module_xchat_get_list((PyObject*)self, args);
- Plugin_SetContext(plugin, saved_context);
- return ret;
-}
-
-/* needed to make context1 == context2 work */
-static PyObject *
-Context_compare(ContextObject *a, ContextObject *b, int op)
-{
- PyObject *ret;
- /* check for == */
- if (op == Py_EQ)
- ret = (a->context == b->context ? Py_True : Py_False);
- /* check for != */
- else if (op == Py_NE)
- ret = (a->context != b->context ? Py_True : Py_False);
- /* only makes sense as == and != */
- else
- {
- PyErr_SetString(PyExc_TypeError, "contexts are either equal or not equal");
- ret = Py_None;
- }
-
- Py_INCREF(ret);
- return ret;
-}
-
-static PyMethodDef Context_methods[] = {
- {"set", (PyCFunction) Context_set, METH_NOARGS},
- {"command", (PyCFunction) Context_command, METH_VARARGS},
- {"prnt", (PyCFunction) Context_prnt, METH_VARARGS},
- {"emit_print", (PyCFunction) Context_emit_print, METH_VARARGS|METH_KEYWORDS},
- {"get_info", (PyCFunction) Context_get_info, METH_VARARGS},
- {"get_list", (PyCFunction) Context_get_list, METH_VARARGS},
- {NULL, NULL}
-};
-
-static PyTypeObject Context_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "hexchat.Context", /*tp_name*/
- sizeof(ContextObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- Context_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- PyObject_GenericGetAttr,/*tp_getattro*/
- PyObject_GenericSetAttr,/*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- (richcmpfunc)Context_compare, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- Context_methods, /*tp_methods*/
- 0, /*tp_members*/
- 0, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- 0, /*tp_init*/
- PyType_GenericAlloc, /*tp_alloc*/
- PyType_G