1 /* ctrlproxy: A modular IRC proxy
2 * (c) 2002-2009 Jelmer Vernooij <jelmer@nl.linux.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "ctrlproxy.h"
23 #include "libirc/python/irc.h"
25 void g_error_set_python(GError **error)
27 PyObject *exception_type, *exception_value, *exception_tb;
31 PyErr_Fetch(&exception_type, &exception_value, &exception_tb);
33 g_set_error_literal(error, g_quark_from_static_string("libirc-python-error"), 1, PyString_AsString(exception_value));
36 static const struct irc_client_callbacks py_client_callbacks;
37 const char *get_my_hostname() { return NULL; /* FIXME */ }
38 void log_global(enum log_level ll, const char *fmt, ...) { /* FIXME */}
40 PyObject *py_line_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
45 char *kwnames[] = { "data", NULL };
47 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &arg))
50 l = PyObject_AsLine(arg);
54 self = (PyLineObject *)type->tp_alloc(type, 0);
62 return (PyObject *)self;
65 static void py_line_dealloc(PyLineObject *self)
67 free_line((struct irc_line *)self->line);
70 static PyObject *py_line_str(PyLineObject *self)
74 str = irc_line_string(self->line);
75 ret = PyString_FromString(str);
80 static PyObject *py_line_repr(PyLineObject *self)
84 str = irc_line_string(self->line);
85 ret = PyString_FromFormat("Line('%s')", str);
90 static PyObject *py_line_get_nick(PyLineObject *self)
92 char *str = line_get_nick(self->line);
93 PyObject *ret = PyString_FromString(str);
98 static PyMethodDef py_line_methods[] = {
99 { "get_nick", (PyCFunction)py_line_get_nick, METH_NOARGS,
100 "Obtain the nick of the user that sent this line." },
104 static Py_ssize_t py_line_length(PyLineObject *self)
106 return self->line->argc;
109 static PyObject *py_line_item(PyLineObject *self, Py_ssize_t i)
111 if (i >= self->line->argc) {
112 PyErr_SetString(PyExc_KeyError, "No such element");
115 return PyString_FromString(self->line->args[i]);
118 static PySequenceMethods py_line_sequence = {
119 .sq_length = (lenfunc)py_line_length,
120 .sq_item = (ssizeargfunc)py_line_item,
123 static PyObject *py_line_get_origin(PyLineObject *self, void *closure)
125 if (self->line->origin != NULL) {
126 return PyString_FromString(self->line->origin);
132 static PyGetSetDef py_line_getsetters[] = {
133 { "origin", (getter)py_line_get_origin, NULL, "Sender of line" },
137 PyTypeObject PyLineType = {
139 .tp_new = py_line_new,
140 .tp_dealloc = (destructor)py_line_dealloc,
141 .tp_flags = Py_TPFLAGS_DEFAULT,
142 .tp_basicsize = sizeof(PyLineObject),
143 .tp_str = (reprfunc)py_line_str,
144 .tp_repr = (reprfunc)py_line_repr,
145 .tp_methods = py_line_methods,
146 .tp_doc = "A RFC2459-compatible line.",
147 .tp_getset = py_line_getsetters,
148 .tp_as_sequence = &py_line_sequence,
151 struct irc_line *PyObject_AsLine(PyObject *obj)
153 if (PyString_Check(obj))
154 return irc_parse_line(PyString_AsString(obj));
156 if (PyObject_TypeCheck(obj, &PyLineType))
157 return linedup(((PyLineObject *)obj)->line);
159 if (PyList_Check(obj)) {
160 struct irc_line *l = g_new0(struct irc_line, 1);
163 if (PyList_Size(obj) > 0) {
164 PyObject *item0 = PyList_GetItem(obj, offset);
165 if (PyString_Check(item0) && PyString_AsString(item0)[0] == ':') {
166 l->origin = g_strdup(PyString_AsString(item0)+1);
170 l->argc = PyList_Size(obj) - offset;
171 l->args = g_new0(char *, l->argc + 1);
172 for (i = 0; i < l->argc; i++) {
173 PyObject *item = PyList_GetItem(obj, offset+i);
174 if (!PyString_Check(item)) {
175 PyErr_SetNone(PyExc_TypeError);
179 l->args[i] = g_strdup(PyString_AsString(item));
185 PyErr_SetString(PyExc_TypeError, "Expected line");
189 static int py_g_list_iter_dealloc(PyGListIterObject *self)
191 Py_XDECREF(self->parent);
196 static PyObject *py_g_list_iter_next(PyGListIterObject *self)
200 if (self->iter == NULL) {
201 PyErr_SetNone(PyExc_StopIteration);
205 ret = self->converter(self->parent, self->iter->data);
207 self->iter = g_list_next(self->iter);
212 static PyTypeObject PyGListIterType = {
213 .tp_name = "GListIter",
214 .tp_dealloc = (destructor)py_g_list_iter_dealloc,
215 .tp_iter = PyObject_SelfIter,
216 .tp_flags = Py_TPFLAGS_DEFAULT,
217 .tp_basicsize = sizeof(PyGListIterObject),
218 .tp_iternext = (iternextfunc)py_g_list_iter_next,
221 PyObject *py_g_list_iter(GList *list, PyObject *parent, PyObject *(*converter) (PyObject *parent, void *))
223 PyGListIterObject *ret = PyObject_New(PyGListIterObject, &PyGListIterType);
231 ret->converter = converter;
233 ret->parent = parent;
234 return (PyObject *)ret;
239 struct irc_client *client;
242 static PyObject *py_client_set_charset(PyClientObject *self, PyObject *args)
247 if (!PyArg_ParseTuple(args, "s", &name))
250 ret = client_set_charset(self->client, name);
252 PyErr_SetString(PyExc_RuntimeError, "Unable to set character set");
259 static PyObject *py_client_send_line(PyClientObject *self, PyObject *args)
263 GError *error = NULL;
264 if (!PyArg_ParseTuple(args, "O", &py_line))
267 l = PyObject_AsLine(py_line);
271 if (!client_send_line(self->client, l, &error)) {
272 PyErr_Format(PyExc_RuntimeError, "Error while sending line: %s", error->message);
282 static PyObject *py_client_send_state(PyClientObject *self, PyNetworkStateObject *state)
284 if (!PyObject_TypeCheck(state, &PyNetworkStateType)) {
285 PyErr_SetNone(PyExc_TypeError);
289 client_send_state(self->client, state->state);
294 static PyObject *py_client_send_state_diff(PyClientObject *self, PyObject *args)
296 PyNetworkStateObject *state1, *state2;
298 if (!PyArg_ParseTuple(args, "OO", &state1, &state2))
301 if (!PyObject_TypeCheck(state1, &PyNetworkStateType) ||
302 !PyObject_TypeCheck(state2, &PyNetworkStateType)) {
303 PyErr_SetNone(PyExc_TypeError);
307 client_send_state_diff(self->client, state1->state, state2->state);
312 static PyObject *py_client_send_motd(PyClientObject *self, PyObject *py_motd)
316 if (!PyList_Check(py_motd)) {
317 PyErr_SetNone(PyExc_TypeError);
321 motd = g_new0(char *, PyList_Size(py_motd) + 1);
323 for (i = 0; i < PyList_Size(py_motd); i++) {
324 PyObject *item = PyList_GetItem(py_motd, i);
325 if (!PyString_Check(item)) {
326 PyErr_SetNone(PyExc_TypeError);
331 motd[i] = PyString_AsString(item);
335 client_send_motd(self->client, motd);
342 static PyObject *py_client_send_channel_mode(PyClientObject *self, PyChannelStateObject *py_channel)
344 if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
345 PyErr_SetNone(PyExc_TypeError);
349 client_send_channel_mode(self->client, py_channel->state);
355 static PyObject *py_client_send_topic(PyClientObject *self, PyObject *args)
357 PyChannelStateObject *py_channel;
358 int explicit = FALSE;
360 if (!PyArg_ParseTuple(args, "O|i", &py_channel, &explicit))
363 if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
364 PyErr_SetNone(PyExc_TypeError);
368 client_send_topic(self->client, py_channel->state, explicit);
373 static PyObject *py_client_send_banlist(PyClientObject *self, PyChannelStateObject *py_channel)
375 if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
376 PyErr_SetNone(PyExc_TypeError);
380 client_send_banlist(self->client, py_channel->state);
385 static PyObject *py_client_send_channel_state(PyClientObject *self, PyChannelStateObject *py_channel)
387 if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
388 PyErr_SetNone(PyExc_TypeError);
392 client_send_channel_state(self->client, py_channel->state);
397 static PyObject *py_client_send_channel_state_diff(PyClientObject *self, PyObject *args)
399 PyChannelStateObject *py_channel1, *py_channel2;
401 if (!PyArg_ParseTuple(args, "OO", &py_channel1, &py_channel2))
404 if (!PyObject_TypeCheck(py_channel1, &PyChannelStateType) ||
405 !PyObject_TypeCheck(py_channel2, &PyChannelStateType)) {
406 PyErr_SetNone(PyExc_TypeError);
410 client_send_channel_state_diff(self->client, py_channel1->state,
418 static PyObject *py_client_send_nameslist(PyClientObject *self, PyChannelStateObject *py_channel)
420 if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
421 PyErr_SetNone(PyExc_TypeError);
425 client_send_nameslist(self->client, py_channel->state);
432 static PyObject *py_client_send_luserchannels(PyClientObject *self, PyObject *arg)
434 if (!PyInt_Check(arg)) {
435 PyErr_SetNone(PyExc_TypeError);
439 client_send_luserchannels(self->client, PyInt_AsLong(arg));
444 static PyObject *py_client_send_netsplit(PyClientObject *self, PyObject *args)
446 char *own_name, *other_name;
448 if (!PyArg_ParseTuple(args, "ss", &own_name, &other_name))
451 client_send_netsplit(self->client, own_name, other_name);
456 static PyObject *py_client_inject_line(PyClientObject *self, PyObject *line)
461 if (self->client->transport == NULL || self->client->transport->callbacks == NULL || self->client->transport->callbacks->recv == NULL) {
462 PyErr_SetNone(PyExc_AttributeError);
466 l = PyObject_AsLine(line);
471 ret = self->client->transport->callbacks->recv(self->client->transport, l);
474 return PyBool_FromLong(ret);
477 static PyObject *py_client_welcome(PyClientObject *self)
482 static PyMethodDef py_client_methods[] = {
483 { "set_charset", (PyCFunction)py_client_set_charset,
485 "Change the character set."
486 ":note: None will disable character conversion."
488 { "send_line", (PyCFunction)py_client_send_line,
490 "Send a line to this client." },
491 { "send_state", (PyCFunction)py_client_send_state,
493 "Send a network state to a client." },
494 { "send_topic", (PyCFunction)py_client_send_topic,
496 "Send the topic of a channel to the client." },
497 { "send_state_diff", (PyCFunction)py_client_send_state_diff,
499 "Send the diff between two states to a client." },
500 { "send_motd", (PyCFunction)py_client_send_motd,
502 "Send a MOTD to a client." },
503 { "send_channel_mode", (PyCFunction)py_client_send_channel_mode,
505 "Send the mode for a channel to a client." },
506 { "send_banlist", (PyCFunction)py_client_send_banlist,
508 "Send the banlist for a channel to a client." },
509 { "send_channel_state", (PyCFunction)py_client_send_channel_state,
511 "Send the state of a channel to a client." },
512 { "send_channel_state_diff", (PyCFunction)py_client_send_channel_state_diff,
514 "Send the diff between two channel states to a client." },
515 { "send_nameslist", (PyCFunction)py_client_send_nameslist,
517 "Send the names for a channel to a client." },
518 { "send_luserchannels", (PyCFunction)py_client_send_luserchannels,
520 "Send number of user channels to client." },
521 { "send_netsplit", (PyCFunction)py_client_send_netsplit,
522 METH_VARARGS, "Send netsplit to a client." },
523 { "inject_line", (PyCFunction)py_client_inject_line,
524 METH_O, "Inject a line." },
525 { "welcome", (PyCFunction)py_client_welcome,
526 METH_NOARGS, "Dummy function, meant to be overridden" },
530 static PyObject *py_client_get_state(PyClientObject *self, void *closure)
532 PyNetworkStateObject *ret;
534 if (self->client->state == NULL)
537 ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
544 ret->parent = (PyObject *)self;
545 ret->state = self->client->state;
547 return (PyObject *)ret;
550 static PyObject *py_client_get_default_target(PyClientObject *self, void *closure)
552 return PyString_FromString(client_get_default_target(self->client));
555 static PyObject *py_client_get_own_hostmask(PyClientObject *self, void *closure)
557 const char *hostmask = client_get_own_hostmask(self->client);
558 if (hostmask == NULL)
560 return PyString_FromString(hostmask);
563 static PyObject *py_client_get_default_origin(PyClientObject *self, void *closure)
565 return PyString_FromString(self->client->default_origin);
568 static PyObject *py_client_get_last_ping(PyClientObject *self, void *closure)
570 return PyLong_FromLong(self->client->last_ping);
573 static PyObject *py_client_get_last_pong(PyClientObject *self, void *closure)
575 return PyLong_FromLong(self->client->last_pong);
578 static PyObject *py_client_get_description(PyClientObject *self, void *closure)
580 return PyString_FromString(self->client->description);
583 static PyObject *py_client_get_authenticated(PyClientObject *self, void *closure)
585 return PyBool_FromLong(self->client->authenticated);
588 static PyObject *py_client_get_transport(PyClientObject *self, void *closure)
590 if (self->client->transport == NULL)
593 if (self->client->transport->backend_ops == &py_transport_ops) {
594 PyObject *ret = (PyObject *)self->client->transport->backend_data;
598 PyTransportObject *ret;
599 ret = PyObject_New(PyTransportObject, &PyTransportType);
606 ret->parent = (PyObject *)self;
607 ret->transport = self->client->transport;
608 return (PyObject *)ret;
612 static PyGetSetDef py_client_getsetters[] = {
613 { "state", (getter)py_client_get_state, NULL, "State" },
614 { "default_target", (getter)py_client_get_default_target, NULL, "Default target" },
615 { "own_hostmask", (getter)py_client_get_own_hostmask, NULL, "Own hostmask" },
616 { "default_origin", (getter)py_client_get_default_origin, NULL,
617 "Default origin that is used to send lines to this client." },
618 { "last_ping", (getter)py_client_get_last_ping, NULL,
619 "Timestamp of the last moment this client pinged the server." },
620 { "last_pong", (getter)py_client_get_last_pong, NULL,
621 "Timestamp of the last pong that was received." },
622 { "description", (getter)py_client_get_description, NULL,
623 "Description of the client" },
624 { "authenticated", (getter)py_client_get_authenticated, NULL,
626 { "transport", (getter)py_client_get_transport, NULL,
631 static PyObject *py_client_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
634 PyObject *py_transport;
635 struct irc_transport *transport;
636 char *default_origin, *desc;
637 char *kwnames[] = { "transport", "default_origin", "desc", NULL };
639 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss", kwnames, &py_transport, &default_origin, &desc))
642 ret = (PyClientObject *)type->tp_alloc(type, 0);
648 transport = wrap_py_transport(py_transport);
650 ret->client = irc_client_new(transport, default_origin, desc, &py_client_callbacks);
651 ret->client->private_data = ret;
653 return (PyObject *)ret;
656 PyTypeObject PyClientType = {
658 .tp_flags = Py_TPFLAGS_DEFAULT,
659 .tp_new = py_client_new,
660 .tp_methods = py_client_methods,
661 .tp_getset = py_client_getsetters,
662 .tp_basicsize = sizeof(PyClientObject)
665 static PyObject *py_network_connect(PyNetworkObject *self)
667 if (!connect_network(self->network)) {
668 PyErr_SetString(PyExc_RuntimeError, "Unable to connect to network");
675 static PyObject *py_network_disconnect(PyNetworkObject *self)
677 disconnect_network(self->network);
682 static PyObject *py_network_send_line(PyNetworkObject *self, PyObject *args)
684 PyObject *py_line, *py_client = Py_None;
687 if (!PyArg_ParseTuple(args, "O|O", &py_line, &py_client))
690 l = PyObject_AsLine(py_line);
694 if (!network_send_line(self->network, NULL, l)) {
695 PyErr_SetString(PyExc_RuntimeError, "Error sending line to network");
703 static PyObject *py_network_set_charset(PyNetworkObject *self, PyObject *args)
706 if (!PyArg_ParseTuple(args, "s", &name))
709 if (!network_set_charset(self->network, name)) {
710 PyErr_SetString(PyExc_RuntimeError, "Unable to set character set");
717 static PyObject *py_network_next_server(PyNetworkObject *self)
719 irc_network_select_next_server(self->network);
723 static PyObject *py_network_feature_string(PyNetworkObject *self)
725 char *str = network_generate_feature_string(self->network);
726 PyObject *ret = PyString_FromString(str);
731 static PyMethodDef py_network_methods[] = {
732 { "connect", (PyCFunction)py_network_connect, METH_NOARGS,
734 { "disconnect", (PyCFunction)py_network_disconnect, METH_NOARGS,
736 { "send_line", (PyCFunction)py_network_send_line, METH_VARARGS,
738 { "set_charset", (PyCFunction)py_network_set_charset, METH_VARARGS,
739 "Change the character set used to communicate with the network." },
740 { "next_server", (PyCFunction)py_network_next_server, METH_NOARGS,
741 "Switch to the next server in the list." },
742 { "feature_string", (PyCFunction)py_network_feature_string, METH_NOARGS,
743 "Obtain the feature list for this network." },
747 static void py_network_dealloc(PyNetworkObject *self)
749 irc_network_unref(self->network);
753 static PyObject *py_network_repr(PyNetworkObject *self)
755 return PyString_FromFormat("<Network '%s'>", self->network->name);
758 static PyObject *py_network_get_name(PyNetworkObject *self, void *closure)
760 return PyString_FromString(self->network->name);
763 static PyObject *py_network_get_reconnect_interval(PyNetworkObject *self, void *closure)
765 return PyInt_FromLong(self->network->reconnect_interval);
768 static int py_network_set_reconnect_interval(PyNetworkObject *self, PyObject *value, void *closure)
770 if (!PyInt_Check(value)) {
771 PyErr_SetNone(PyExc_TypeError);
775 self->network->reconnect_interval = PyInt_AsLong(value);
779 static PyObject *py_network_get_info(PyNetworkObject *self, void *closure)
781 PyNetworkInfoObject *pyinfo = PyObject_New(PyNetworkInfoObject, &PyNetworkInfoType);
783 if (pyinfo == NULL) {
789 pyinfo->parent = (PyObject *)self;
790 pyinfo->info = self->network->info;
792 return (PyObject *)pyinfo;
795 static PyObject *py_network_get_internal_state(PyNetworkObject *self, void *closure)
797 PyNetworkStateObject *ret;
799 if (self->network->internal_state == NULL)
802 ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
809 ret->parent = (PyObject *)self;
810 ret->state = self->network->internal_state;
812 return (PyObject *)ret;
815 static PyObject *py_network_get_external_state(PyNetworkObject *self, void *closure)
817 PyNetworkStateObject *ret;
819 if (self->network->external_state == NULL)
822 ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
829 ret->parent = (PyObject *)self;
830 ret->state = self->network->external_state;
832 return (PyObject *)ret;
835 static PyObject *py_network_get_linestack_errors(PyNetworkObject *self, void *closure)
837 return PyInt_FromLong(self->network->linestack_errors);
840 static PyObject *PyClientFromPtr(struct irc_client *c)
842 PyClientObject *ret = PyObject_New(PyClientObject, &PyClientType);
850 return (PyObject *)ret;
853 static void *PyPtrFromClient(PyObject *obj)
855 if (!PyObject_TypeCheck(obj, &PyClientType)) {
856 PyErr_SetNone(PyExc_TypeError);
860 return ((PyClientObject *)obj)->client;
863 static PyObject *py_network_get_query_stack(PyNetworkObject *self, void *closure)
865 PyQueryStackObject *ret = PyObject_New(PyQueryStackObject, &PyQueryStackType);
871 ret->stack = self->network->queries;
872 ret->import_userdata = (PyObject *(*)(void *))PyClientFromPtr;
873 ret->export_userdata = PyPtrFromClient;
875 ret->parent = (PyObject *)self;
877 return (PyObject *)ret;
880 static PyGetSetDef py_network_getsetters[] = {
881 { "name", (getter)py_network_get_name, NULL, "Name of the network" },
882 { "reconnect_interval", (getter)py_network_get_reconnect_interval, (setter)py_network_set_reconnect_interval, "Reconnect interval" },
883 { "info", (getter)py_network_get_info, NULL, "Info" },
884 { "internal_state", (getter) py_network_get_internal_state, NULL, "Internal state" },
885 { "external_state", (getter) py_network_get_external_state, NULL, "External state" },
886 { "linestack_errors", (getter) py_network_get_linestack_errors, NULL, "Number of linestack errors that has occurred so far" },
887 { "query_stack", (getter)py_network_get_query_stack, NULL, "Query stack" },
891 PyTypeObject PyNetworkType = {
892 .tp_name = "Network",
893 .tp_flags = Py_TPFLAGS_DEFAULT,
894 .tp_methods = py_network_methods,
895 .tp_getset = py_network_getsetters,
896 .tp_repr = (reprfunc)py_network_repr,
897 .tp_basicsize = sizeof(PyNetworkObject),
898 .tp_dealloc = (destructor)py_network_dealloc,
901 static int py_process_from_client(struct irc_client *client, const struct irc_line *line)
903 PyObject *self, *ret;
904 PyLineObject *py_line;
905 self = client->private_data;
906 py_line = PyObject_New(PyLineObject, &PyLineType);
907 py_line->line = linedup(line);
908 ret = PyObject_CallMethod(self, "process_from_client", "O", py_line);
914 static void py_log_client(enum log_level level, const struct irc_client *client, const char *text)
916 PyObject *self, *ret;
917 self = client->private_data;
918 ret = PyObject_CallMethod(self, "log", "is", level, text);
920 PyErr_Clear(); /* FIXME */
926 static int py_process_to_client(struct irc_client *client, const struct irc_line *line)
928 PyObject *self, *ret;
929 PyLineObject *py_line;
931 self = client->private_data;
932 py_line = PyObject_New(PyLineObject, &PyLineType);
933 py_line->line = linedup(line);
935 ret = PyObject_CallMethod(self, "process_to_client", "O", py_line);
938 PyErr_Clear(); /* FIXME: */
946 static int py_welcome_client(struct irc_client *client)
948 PyObject *ret, *self;
949 self = client->private_data;
950 ret = PyObject_CallMethod(self, "welcome", "");
953 if (ret == Py_True || ret == Py_None)
958 static const struct irc_client_callbacks py_client_callbacks = {
959 .log_fn = py_log_client,
960 .process_from_client = py_process_from_client,
961 .process_to_client = py_process_to_client,
962 .welcome = py_welcome_client
965 static PyObject *py_query_stack_record(PyQueryStackObject *self, PyObject *args)
967 PyObject *py_token, *py_line;
969 struct irc_line *line;
971 if (!PyArg_ParseTuple(args, "OO", &py_token, &py_line))
974 line = PyObject_AsLine(py_line);
978 if (self->export_userdata == NULL) {
981 userdata = self->export_userdata(py_token);
982 if (userdata == NULL) {
987 return PyBool_FromLong(query_stack_record(self->stack, userdata, line));
990 static PyObject *py_query_stack_redirect(PyQueryStackObject *self, PyObject *args)
993 struct irc_line *line;
996 if (!PyArg_ParseTuple(args, "O", &py_line))
999 line = PyObject_AsLine(py_line);
1003 ret = (PyObject *)query_stack_match_response(self->stack, line);
1012 static PyObject *py_query_stack_clear(PyQueryStackObject *self)
1014 query_stack_clear(self->stack);
1018 static PyMethodDef py_query_stack_methods[] = {
1019 { "record", (PyCFunction)py_query_stack_record, METH_VARARGS, NULL },
1020 { "response", (PyCFunction)py_query_stack_redirect, METH_VARARGS, NULL },
1021 { "clear", (PyCFunction)py_query_stack_clear, METH_NOARGS, NULL },
1025 static int py_query_stack_dealloc(PyQueryStackObject *self)
1027 if (self->parent != NULL) {
1028 Py_DECREF(self->parent);
1030 query_stack_free(self->stack);
1036 static PyObject *Py_Id(void *obj)
1041 static PyObject *py_query_stack_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1043 PyQueryStackObject *self = (PyQueryStackObject *)type->tp_alloc(type, 0);
1049 self->stack = new_query_stack((void (*)(void *))Py_IncRef, (void (*)(void *))Py_DecRef);
1050 self->import_userdata = Py_Id;
1051 self->export_userdata = NULL;
1052 self->parent = NULL;
1054 return (PyObject *)self;
1057 static PyObject *py_query_stack_entry_from_ptr(PyQueryStackObject *parent, struct query_stack_entry *e)
1059 return Py_BuildValue("(O&sl)", parent->import_userdata, e->userdata, e->query->name, e->time);
1062 static PyObject *py_query_stack_iter(PyQueryStackObject *self)
1064 return py_g_list_iter(self->stack->entries, (PyObject *)self, (PyObject *(*)(PyObject *, void*))py_query_stack_entry_from_ptr);
1067 static Py_ssize_t py_query_stack_len(PyQueryStackObject *self)
1069 return g_list_length(self->stack->entries);
1072 static PySequenceMethods py_query_stack_sequence = {
1073 .sq_length = (lenfunc)py_query_stack_len,
1076 PyTypeObject PyQueryStackType = {
1077 .tp_name = "QueryStack",
1078 .tp_flags = Py_TPFLAGS_DEFAULT,
1079 .tp_new = py_query_stack_new,
1080 .tp_methods = py_query_stack_methods,
1081 .tp_iter = (getiterfunc)py_query_stack_iter,
1082 .tp_basicsize = sizeof(PyQueryStackObject),
1083 .tp_dealloc = (destructor)py_query_stack_dealloc,
1084 .tp_as_sequence = &py_query_stack_sequence,
1088 static PyMethodDef irc_methods[] = {
1096 if (PyType_Ready(&PyLineType) < 0)
1099 if (PyType_Ready(&PyClientType) < 0)
1102 if (PyType_Ready(&PyNetworkInfoType) < 0)
1105 if (PyType_Ready(&PyNetworkStateType) < 0)
1108 if (PyType_Ready(&PyNetworkType) < 0)
1111 if (PyType_Ready(&PyChannelStateType) < 0)
1114 if (PyType_Ready(&PyNetworkNickType) < 0)
1117 if (PyType_Ready(&PyChannelModeDictType) < 0)
1120 if (PyType_Ready(&PyNetworkChannelDictType) < 0)
1123 if (PyType_Ready(&PyGListIterType) < 0)
1126 if (PyType_Ready(&PyQueryStackType) < 0)
1129 if (PyType_Ready(&PyTransportType) < 0)
1132 if (PyType_Ready(&PyLinestackType) < 0)
1135 if (PyType_Ready(&PyChannelModeDictType) < 0)
1138 if (PyType_Ready(&PyChannelNickDictType) < 0)
1141 m = Py_InitModule3("irc", irc_methods,
1142 "Simple IRC protocol module for Python.");
1146 Py_INCREF(&PyLineType);
1147 PyModule_AddObject(m, "Line", (PyObject *)&PyLineType);
1148 Py_INCREF(&PyNetworkInfoType);
1149 PyModule_AddObject(m, "NetworkInfo", (PyObject *)&PyNetworkInfoType);
1150 Py_INCREF(&PyNetworkStateType);
1151 PyModule_AddObject(m, "NetworkState", (PyObject *)&PyNetworkStateType);
1152 Py_INCREF(&PyChannelStateType);
1153 PyModule_AddObject(m, "ChannelState", (PyObject *)&PyChannelStateType);
1154 Py_INCREF(&PyNetworkNickType);
1155 PyModule_AddObject(m, "Nick", (PyObject *)&PyNetworkNickType);
1156 Py_INCREF(&PyClientType);
1157 PyModule_AddObject(m, "Client", (PyObject *)&PyClientType);
1158 Py_INCREF(&PyNetworkType);
1159 PyModule_AddObject(m, "Network", (PyObject *)&PyNetworkType);
1160 Py_INCREF(&PyQueryStackType);
1161 PyModule_AddObject(m, "QueryStack", (PyObject *)&PyQueryStackType);
1162 Py_INCREF(&PyTransportType);
1163 PyModule_AddObject(m, "Transport", (PyObject *)&PyTransportType);
1164 Py_INCREF(&PyLinestackType);
1165 PyModule_AddObject(m, "Linestack", (PyObject *)&PyLinestackType);
1166 PyModule_AddIntConstant(m, "TO_SERVER", TO_SERVER);
1167 PyModule_AddIntConstant(m, "FROM_SERVER", FROM_SERVER);