summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTingPing <tngpng@gmail.com>2013-07-19 10:25:46 -0400
committerTingPing <tingping@tingping.se>2013-09-15 02:45:37 -0400
commit414b591358c1c97c05dda94e27df0de3d9e531a7 (patch)
tree662475aba315c7e9a0a5d55492d944b0067906e7
parentccd4945504a5db0a4f1334c31da6eec026dbb9d0 (diff)
Python: Add support for attributes in hooks
-rw-r--r--plugins/python/python.c274
1 files changed, 264 insertions, 10 deletions
diff --git a/plugins/python/python.c b/plugins/python/python.c
index b34ed0a9..ea16438b 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -211,7 +211,8 @@ static PyThreadState *pTempThread;
 	((PluginObject *)(x))->gui = (y);
 
 #define HOOK_XCHAT  1
-#define HOOK_UNLOAD 2
+#define HOOK_XCHAT_ATTR 2
+#define HOOK_UNLOAD 3
 
 /* ===================================================================== */
 /* Object definitions */
@@ -228,6 +229,11 @@ typedef struct {
 
 typedef struct {
 	PyObject_HEAD
+	PyObject *time;
+} AttributeObject;
+
+typedef struct {
+	PyObject_HEAD
 	const char *listname;
 	PyObject *dict;
 } ListItemObject;
@@ -261,8 +267,9 @@ static PyObject *Util_BuildList(char *word[]);
 static void Util_Autoload();
 static char *Util_Expand(char *filename);
 
+static int Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata);
 static int Callback_Command(char *word[], char *word_eol[], void *userdata);
-static int Callback_Print(char *word[], void *userdata);
+static int Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata);
 static int Callback_Timer(void *userdata);
 static int Callback_ThreadTimer(void *userdata);
 
@@ -270,6 +277,8 @@ static PyObject *XChatOut_New();
 static PyObject *XChatOut_write(PyObject *self, PyObject *args);
 static void XChatOut_dealloc(PyObject *self);
 
+static PyObject *Attribute_New(hexchat_event_attrs *attrs);
+
 static void Context_dealloc(PyObject *self);
 static PyObject *Context_set(ContextObject *self, PyObject *args);
 static PyObject *Context_command(ContextObject *self, PyObject *args);
@@ -331,6 +340,7 @@ static PyTypeObject Plugin_Type;
 static PyTypeObject XChatOut_Type;
 static PyTypeObject Context_Type;
 static PyTypeObject ListItem_Type;
+static PyTypeObject Attribute_Type;
 
 static PyThreadState *main_tstate = NULL;
 static void *thread_timer = NULL;
@@ -488,6 +498,58 @@ Util_ReleaseThread(PyThreadState *tstate)
  * the load function, and the hooks for interactive interpreter. */
 
 static int
+Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata)
+{
+	Hook *hook = (Hook *) userdata;
+	PyObject *retobj;
+	PyObject *word_list, *word_eol_list;
+	PyObject *attributes;
+	int ret = 0;
+	PyObject *plugin;
+
+	plugin = hook->plugin;
+	BEGIN_PLUGIN(plugin);
+
+	word_list = Util_BuildList(word+1);
+	if (word_list == NULL) {
+		END_PLUGIN(plugin);
+		return 0;
+	}
+	word_eol_list = Util_BuildList(word_eol+1);
+	if (word_eol_list == NULL) {
+		Py_DECREF(word_list);
+		END_PLUGIN(plugin);
+		return 0;
+	}
+
+	attributes = Attribute_New(attrs);
+
+	if (hook->type == HOOK_XCHAT_ATTR)
+		retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list,
+					       word_eol_list, hook->userdata, attributes);
+	else
+		retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
+					       word_eol_list, hook->userdata);
+	Py_DECREF(word_list);
+	Py_DECREF(word_eol_list);
+	Py_DECREF(attributes);
+
+	if (retobj == Py_None) {
+		ret = HEXCHAT_EAT_NONE;
+		Py_DECREF(retobj);
+	} else if (retobj) {
+		ret = PyLong_AsLong(retobj);
+		Py_DECREF(retobj);
+	} else {
+		PyErr_Print();
+	}
+
+	END_PLUGIN(plugin);
+
+	return ret;
+}
+
+static int
 Callback_Command(char *word[], char *word_eol[], void *userdata)
 {
 	Hook *hook = (Hook *) userdata;
@@ -534,12 +596,13 @@ Callback_Command(char *word[], char *word_eol[], void *userdata)
 /* No Callback_Server() here. We use Callback_Command() as well. */
 
 static int
-Callback_Print(char *word[], void *userdata)
+Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata)
 {
 	Hook *hook = (Hook *) userdata;
 	PyObject *retobj;
 	PyObject *word_list;
 	PyObject *word_eol_list;
+	PyObject *attributes;
 	char **word_eol;
 	char *word_eol_raw;
 	int listsize = 0;
@@ -597,10 +660,18 @@ Callback_Print(char *word[], void *userdata)
 		return 0;
 	}
 
-	retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list,
-				       word_eol_list, hook->userdata);
+	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);
 
 	g_free(word_eol_raw);
 	g_free(word_eol);
@@ -823,6 +894,84 @@ static PyTypeObject XChatOut_Type = {
 
 
 /* ===================================================================== */
+/* Attribute object */
+
+#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
@@ -1232,7 +1381,7 @@ Plugin_RemoveHook(PyObject *plugin, Hook *hook)
 	list = g_slist_find(Plugin_GetHooks(plugin), hook);
 	if (list) {
 		/* Ok, unhook it. */
-		if (hook->type == HOOK_XCHAT) {
+		if (hook->type != HOOK_UNLOAD) {
 			/* This is an xchat hook. Unregister it. */
 			BEGIN_XCHAT_CALLS(NONE);
 			hexchat_unhook(ph, (hexchat_hook*)hook->data);
@@ -1255,7 +1404,7 @@ Plugin_RemoveAllHooks(PyObject *plugin)
 	GSList *list = Plugin_GetHooks(plugin);
 	while (list) {
 		Hook *hook = (Hook *) list->data;
-		if (hook->type == HOOK_XCHAT) {
+		if (hook->type != HOOK_UNLOAD) {
 			/* This is an xchat hook. Unregister it. */
 			BEGIN_XCHAT_CALLS(NONE);
 			hexchat_unhook(ph, (hexchat_hook*)hook->data);
@@ -1531,6 +1680,33 @@ Module_hexchat_emit_print(PyObject *self, PyObject *args)
 }
 
 static PyObject *
+Module_hexchat_emit_print_at(PyObject *self, PyObject *args)
+{
+	char *argv[10];
+	char *name;
+	long time;
+	int res;
+	hexchat_event_attrs* attrs;
+	memset(&argv, 0, sizeof(char*)*10);
+	if (!PyArg_ParseTuple(args, "ls|ssssss:print_event_at", &time, &name,
+			      &argv[0], &argv[1], &argv[2],
+			      &argv[3], &argv[4], &argv[5],
+			      &argv[6], &argv[7], &argv[8]))
+		return NULL;
+	BEGIN_XCHAT_CALLS(RESTORE_CONTEXT|ALLOW_THREADS);
+	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],
+					 argv[6], argv[7], argv[8]);
+
+	hexchat_event_attrs_free(ph, attrs);
+	END_XCHAT_CALLS();
+	return PyLong_FromLong(res);
+}
+
+static PyObject *
 Module_hexchat_get_info(PyObject *self, PyObject *args)
 {
 	const char *info;
@@ -1789,8 +1965,44 @@ Module_hexchat_hook_server(PyObject *self, PyObject *args, PyObject *kwargs)
 		return NULL;
 
 	BEGIN_XCHAT_CALLS(NONE);
-	hook->data = (void*)hexchat_hook_server(ph, name, priority,
-					      Callback_Command, hook);
+	hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority,
+					      Callback_Server, hook);
+	END_XCHAT_CALLS();
+
+	return PyLong_FromLong((long)hook);
+}
+
+static PyObject *
+Module_hexchat_hook_server_attrs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	char *name;
+	PyObject *callback;
+	PyObject *userdata = Py_None;
+	int priority = HEXCHAT_PRI_NORM;
+	PyObject *plugin;
+	Hook *hook;
+	char *kwlist[] = {"name", "callback", "userdata", "priority", 0};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_server",
+					 kwlist, &name, &callback, &userdata,
+					 &priority))
+		return NULL;
+
+	plugin = Plugin_GetCurrent();
+	if (plugin == NULL)
+		return NULL;
+	if (!PyCallable_Check(callback)) {
+		PyErr_SetString(PyExc_TypeError, "callback is not callable");
+		return NULL;
+	}
+
+	hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, NULL, NULL);
+	if (hook == NULL)
+		return NULL;
+
+	BEGIN_XCHAT_CALLS(NONE);
+	hook->data = (void*)hexchat_hook_server_attrs(ph, name, priority,
+					      Callback_Server, hook);
 	END_XCHAT_CALLS();
 
 	return PyLong_FromLong((long)hook);
@@ -1825,7 +2037,43 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs)
 		return NULL;
 
 	BEGIN_XCHAT_CALLS(NONE);
-	hook->data = (void*)hexchat_hook_print(ph, name, priority,
+	hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority,
+					     Callback_Print, hook);
+	END_XCHAT_CALLS();
+
+	return PyLong_FromLong((long)hook);
+}
+
+static PyObject *
+Module_hexchat_hook_print_attrs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	char *name;
+	PyObject *callback;
+	PyObject *userdata = Py_None;
+	int priority = HEXCHAT_PRI_NORM;
+	PyObject *plugin;
+	Hook *hook;
+	char *kwlist[] = {"name", "callback", "userdata", "priority", 0};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|Oi:hook_print_attrs",
+					 kwlist, &name, &callback, &userdata,
+					 &priority))
+		return NULL;
+
+	plugin = Plugin_GetCurrent();
+	if (plugin == NULL)
+		return NULL;
+	if (!PyCallable_Check(callback)) {
+		PyErr_SetString(PyExc_TypeError, "callback is not callable");
+		return NULL;
+	}
+
+	hook = Plugin_AddHook(HOOK_XCHAT_ATTR, plugin, callback, userdata, name, NULL);
+	if (hook == NULL)
+		return NULL;
+
+	BEGIN_XCHAT_CALLS(NONE);
+	hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority,
 					     Callback_Print, hook);
 	END_XCHAT_CALLS();
 
@@ -2068,6 +2316,8 @@ static PyMethodDef Module_xchat_methods[] = {
 		METH_VARARGS},
 	{"emit_print",		Module_hexchat_emit_print,
 		METH_VARARGS},
+	{"emit_print_at",	Module_hexchat_emit_print_at,
+		METH_VARARGS},
 	{"get_info",		Module_hexchat_get_info,
 		METH_VARARGS},
 	{"get_prefs",		Module_xchat_get_prefs,
@@ -2088,8 +2338,12 @@ static PyMethodDef Module_xchat_methods[] = {
 		METH_VARARGS|METH_KEYWORDS},
 	{"hook_server",		(PyCFunction)Module_hexchat_hook_server,
 		METH_VARARGS|METH_KEYWORDS},
+	{"hook_server_attrs",		(PyCFunction)Module_hexchat_hook_server_attrs,
+		METH_VARARGS|METH_KEYWORDS},
 	{"hook_print",		(PyCFunction)Module_hexchat_hook_print,
 		METH_VARARGS|METH_KEYWORDS},
+	{"hook_print_attrs",		(PyCFunction)Module_hexchat_hook_print_attrs,
+		METH_VARARGS|METH_KEYWORDS},
 	{"hook_timer",		(PyCFunction)Module_hexchat_hook_timer,
 		METH_VARARGS|METH_KEYWORDS},
 	{"hook_unload",		(PyCFunction)Module_hexchat_hook_unload,