8cc26fd2334a554691ebd14d7a8804600930fd20
[jelmer/ctrlproxy.git] / libirc / python / irc.c
1 /*    ctrlproxy: A modular IRC proxy
2  *    (c) 2002-2009 Jelmer Vernooij <jelmer@nl.linux.org>
3  *     vim: expandtab
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include <stdbool.h>
21 #include "ctrlproxy.h"
22 #include "redirect.h"
23 #include "libirc/python/irc.h"
24
25 void g_error_set_python(GError **error)
26 {
27     PyObject *exception_type, *exception_value, *exception_tb;
28
29     /* FIXME */
30
31     PyErr_Fetch(&exception_type, &exception_value, &exception_tb);
32
33     g_set_error_literal(error, g_quark_from_static_string("libirc-python-error"), 1, PyString_AsString(exception_value));
34 }
35
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 */}
39
40 PyObject *py_line_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
41 {
42     PyObject *arg;
43     PyLineObject *self;
44     struct irc_line *l;
45     char *kwnames[] = { "data", NULL };
46
47     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &arg))
48         return NULL;
49
50     l = PyObject_AsLine(arg);
51     if (l == NULL)
52         return NULL;
53
54     self = (PyLineObject *)type->tp_alloc(type, 0);
55     if (self == NULL) {
56         PyErr_NoMemory();
57         return NULL;
58     }
59
60     self->line = l;
61
62     return (PyObject *)self;
63 }
64
65 static void py_line_dealloc(PyLineObject *self)
66 {
67     free_line((struct irc_line *)self->line);
68 }
69
70 static PyObject *py_line_str(PyLineObject *self)
71 {
72     char *str;
73     PyObject *ret;
74     str = irc_line_string(self->line);
75     ret = PyString_FromString(str);
76     g_free(str);
77     return ret;
78 }
79
80 static PyObject *py_line_repr(PyLineObject *self)
81 {
82     char *str;
83     PyObject *ret;
84     str = irc_line_string(self->line);
85     ret = PyString_FromFormat("Line('%s')", str);
86     g_free(str);
87     return ret;
88 }
89
90 static PyObject *py_line_get_nick(PyLineObject *self)
91 {
92     char *str = line_get_nick(self->line);
93     PyObject *ret = PyString_FromString(str);
94     g_free(str);
95     return ret;
96 }
97
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." },
101     { NULL }
102 };
103
104 static Py_ssize_t py_line_length(PyLineObject *self)
105 {
106     return self->line->argc;
107 }
108
109 static PyObject *py_line_item(PyLineObject *self, Py_ssize_t i)
110 {
111     if (i >= self->line->argc) {
112         PyErr_SetString(PyExc_KeyError, "No such element");
113         return NULL;
114     }
115     return PyString_FromString(self->line->args[i]);
116 }
117
118 static PySequenceMethods py_line_sequence = {
119     .sq_length = (lenfunc)py_line_length,
120     .sq_item = (ssizeargfunc)py_line_item,
121 };
122
123 static PyObject *py_line_get_origin(PyLineObject *self, void *closure)
124 {
125     if (self->line->origin != NULL) {
126         return PyString_FromString(self->line->origin);
127     } else {
128         Py_RETURN_NONE;
129     }
130 }
131
132 static PyGetSetDef py_line_getsetters[] = {
133     { "origin", (getter)py_line_get_origin, NULL, "Sender of line" },
134     { NULL }
135 };
136
137 PyTypeObject PyLineType = {
138     .tp_name = "Line",
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,
149 };
150
151 struct irc_line *PyObject_AsLine(PyObject *obj)
152 {
153     if (PyString_Check(obj))
154         return irc_parse_line(PyString_AsString(obj));
155
156     if (PyObject_TypeCheck(obj, &PyLineType))
157         return linedup(((PyLineObject *)obj)->line);
158     
159     if (PyList_Check(obj)) {
160         struct irc_line *l = g_new0(struct irc_line, 1);
161         int offset = 0;
162         int i;
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);
167                 offset++;
168             }
169         }
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);
176                 free_line(l);
177                 return NULL;
178             }
179             l->args[i] = g_strdup(PyString_AsString(item));
180         }
181         l->args[i] = NULL;
182         return l;
183     }   
184
185     PyErr_SetString(PyExc_TypeError, "Expected line");
186     return NULL;
187 }
188
189 static int py_g_list_iter_dealloc(PyGListIterObject *self)
190 {
191     Py_XDECREF(self->parent);
192     PyObject_Del(self);
193     return 0;
194 }
195
196 static PyObject *py_g_list_iter_next(PyGListIterObject *self)
197 {
198     PyObject *ret;
199
200     if (self->iter == NULL) {
201         PyErr_SetNone(PyExc_StopIteration);
202         return NULL;
203     }
204     
205     ret = self->converter(self->parent, self->iter->data);
206
207     self->iter = g_list_next(self->iter);
208
209     return ret;
210 }
211
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,
219 };
220
221 PyObject *py_g_list_iter(GList *list, PyObject *parent, PyObject *(*converter) (PyObject *parent, void *))
222 {
223     PyGListIterObject *ret = PyObject_New(PyGListIterObject, &PyGListIterType);
224
225     if (ret == NULL) {
226         PyErr_NoMemory();
227         return NULL;
228     }
229
230     ret->iter = list;
231     ret->converter = converter;
232     Py_INCREF(parent);
233     ret->parent = parent;
234     return (PyObject *)ret;
235 }   
236
237 typedef struct {
238     PyObject_HEAD
239     struct irc_client *client;
240 } PyClientObject;
241
242 static PyObject *py_client_set_charset(PyClientObject *self, PyObject *args)
243 {
244     bool ret;
245     char *name;
246
247     if (!PyArg_ParseTuple(args, "s", &name))
248         return NULL;
249
250     ret = client_set_charset(self->client, name);
251     if (!ret) {
252         PyErr_SetString(PyExc_RuntimeError, "Unable to set character set");
253         return NULL;
254     }
255
256     Py_RETURN_NONE;
257 }
258
259 static PyObject *py_client_send_line(PyClientObject *self, PyObject *args)
260 {
261     PyObject *py_line;
262     struct irc_line *l;
263     GError *error = NULL;
264     if (!PyArg_ParseTuple(args, "O", &py_line))
265         return NULL;
266
267     l = PyObject_AsLine(py_line);
268     if (l == NULL)
269         return NULL;
270
271     if (!client_send_line(self->client, l, &error)) {
272         PyErr_Format(PyExc_RuntimeError, "Error while sending line: %s", error->message);
273         g_error_free(error);
274         free_line(l);
275         return NULL;
276     }
277     free_line(l);
278
279     Py_RETURN_NONE;
280 }
281
282 static PyObject *py_client_send_state(PyClientObject *self, PyNetworkStateObject *state)
283 {
284     if (!PyObject_TypeCheck(state, &PyNetworkStateType)) {
285         PyErr_SetNone(PyExc_TypeError);
286         return NULL;
287     }
288
289     client_send_state(self->client, state->state);
290
291     Py_RETURN_NONE;
292 }
293
294 static PyObject *py_client_send_state_diff(PyClientObject *self, PyObject *args)
295 {
296     PyNetworkStateObject *state1, *state2;
297
298     if (!PyArg_ParseTuple(args, "OO", &state1, &state2))
299         return NULL;
300
301     if (!PyObject_TypeCheck(state1, &PyNetworkStateType) || 
302         !PyObject_TypeCheck(state2, &PyNetworkStateType)) {
303         PyErr_SetNone(PyExc_TypeError);
304         return NULL;
305     }
306
307     client_send_state_diff(self->client, state1->state, state2->state);
308
309     Py_RETURN_NONE;
310 }
311
312 static PyObject *py_client_send_motd(PyClientObject *self, PyObject *py_motd)
313 {
314     char **motd;
315     int i;
316     if (!PyList_Check(py_motd)) {
317         PyErr_SetNone(PyExc_TypeError);
318         return NULL;
319     }
320
321     motd = g_new0(char *, PyList_Size(py_motd) + 1);
322
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);
327             g_free(motd);
328             return NULL;
329         }
330
331         motd[i] = PyString_AsString(item);
332     }
333     motd[i] = NULL;
334
335     client_send_motd(self->client, motd);
336
337     g_free(motd);
338
339     Py_RETURN_NONE;
340 }
341
342 static PyObject *py_client_send_channel_mode(PyClientObject *self, PyChannelStateObject *py_channel)
343 {
344     if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
345         PyErr_SetNone(PyExc_TypeError);
346         return NULL;
347     }
348
349     client_send_channel_mode(self->client, py_channel->state);
350
351     Py_RETURN_NONE;
352 }
353
354
355 static PyObject *py_client_send_topic(PyClientObject *self, PyObject *args)
356 {
357     PyChannelStateObject *py_channel;
358     int explicit = FALSE;  
359
360     if (!PyArg_ParseTuple(args, "O|i", &py_channel, &explicit))
361         return NULL;
362
363     if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
364         PyErr_SetNone(PyExc_TypeError);
365         return NULL;
366     }
367
368     client_send_topic(self->client, py_channel->state, explicit);
369
370     Py_RETURN_NONE;
371 }
372
373 static PyObject *py_client_send_banlist(PyClientObject *self, PyChannelStateObject *py_channel)
374 {
375     if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
376         PyErr_SetNone(PyExc_TypeError);
377         return NULL;
378     }
379
380     client_send_banlist(self->client, py_channel->state);
381
382     Py_RETURN_NONE;
383 }
384
385 static PyObject *py_client_send_channel_state(PyClientObject *self, PyChannelStateObject *py_channel)
386 {
387     if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
388         PyErr_SetNone(PyExc_TypeError);
389         return NULL;
390     }
391
392     client_send_channel_state(self->client, py_channel->state);
393
394     Py_RETURN_NONE;
395 }
396
397 static PyObject *py_client_send_channel_state_diff(PyClientObject *self, PyObject *args)
398 {
399     PyChannelStateObject *py_channel1, *py_channel2;
400
401     if (!PyArg_ParseTuple(args, "OO", &py_channel1, &py_channel2))
402         return NULL;
403
404     if (!PyObject_TypeCheck(py_channel1, &PyChannelStateType) || 
405         !PyObject_TypeCheck(py_channel2, &PyChannelStateType)) {
406         PyErr_SetNone(PyExc_TypeError);
407         return NULL;
408     }
409
410     client_send_channel_state_diff(self->client, py_channel1->state,
411                                    py_channel2->state);
412
413     Py_RETURN_NONE;
414 }
415
416
417
418 static PyObject *py_client_send_nameslist(PyClientObject *self, PyChannelStateObject *py_channel)
419 {
420     if (!PyObject_TypeCheck(py_channel, &PyChannelStateType)) {
421         PyErr_SetNone(PyExc_TypeError);
422         return NULL;
423     }
424
425     client_send_nameslist(self->client, py_channel->state);
426
427     Py_RETURN_NONE;
428 }
429
430
431
432 static PyObject *py_client_send_luserchannels(PyClientObject *self, PyObject *arg)
433 {
434     if (!PyInt_Check(arg)) {
435         PyErr_SetNone(PyExc_TypeError);
436         return NULL;
437     }
438
439     client_send_luserchannels(self->client, PyInt_AsLong(arg));
440
441     Py_RETURN_NONE;
442 }
443
444 static PyObject *py_client_send_netsplit(PyClientObject *self, PyObject *args)
445 {
446     char *own_name, *other_name;
447
448     if (!PyArg_ParseTuple(args, "ss", &own_name, &other_name))
449         return NULL;
450
451     client_send_netsplit(self->client, own_name, other_name);
452
453     Py_RETURN_NONE;
454 }
455
456 static PyObject *py_client_inject_line(PyClientObject *self, PyObject *line)
457 {
458     struct irc_line *l;
459     gboolean ret;
460
461     if (self->client->transport == NULL || self->client->transport->callbacks == NULL || self->client->transport->callbacks->recv == NULL) {
462         PyErr_SetNone(PyExc_AttributeError);
463         return NULL;
464     }
465
466     l = PyObject_AsLine(line);
467     if (l == NULL) {
468         return NULL;
469     }
470
471     ret = self->client->transport->callbacks->recv(self->client->transport, l);
472     free_line(l);
473
474     return PyBool_FromLong(ret);
475 }
476
477 static PyObject *py_client_welcome(PyClientObject *self)
478 {
479     Py_RETURN_NONE;
480 }
481
482 static PyMethodDef py_client_methods[] = {
483     { "set_charset", (PyCFunction)py_client_set_charset, 
484         METH_VARARGS,
485         "Change the character set."  
486         ":note: None will disable character conversion."
487     },
488     { "send_line", (PyCFunction)py_client_send_line,
489         METH_VARARGS,
490         "Send a line to this client." },
491     { "send_state", (PyCFunction)py_client_send_state,
492         METH_O,
493         "Send a network state to a client." },
494     { "send_topic", (PyCFunction)py_client_send_topic,
495         METH_VARARGS,
496         "Send the topic of a channel to the client." },
497     { "send_state_diff", (PyCFunction)py_client_send_state_diff,
498         METH_VARARGS,
499         "Send the diff between two states to a client." },
500     { "send_motd", (PyCFunction)py_client_send_motd,
501         METH_O,
502         "Send a MOTD to a client." },
503     { "send_channel_mode", (PyCFunction)py_client_send_channel_mode,
504         METH_O,
505         "Send the mode for a channel to a client." },
506     { "send_banlist", (PyCFunction)py_client_send_banlist,
507         METH_O,
508         "Send the banlist for a channel to a client." },
509     { "send_channel_state", (PyCFunction)py_client_send_channel_state,
510         METH_O,
511         "Send the state of a channel to a client." },
512     { "send_channel_state_diff", (PyCFunction)py_client_send_channel_state_diff,
513         METH_VARARGS,
514         "Send the diff between two channel states to a client." },
515     { "send_nameslist", (PyCFunction)py_client_send_nameslist,
516         METH_O,
517         "Send the names for a channel to a client." },
518     { "send_luserchannels", (PyCFunction)py_client_send_luserchannels,
519         METH_O,
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" },
527     { NULL }
528 };
529
530 static PyObject *py_client_get_state(PyClientObject *self, void *closure)
531 {
532     PyNetworkStateObject *ret;
533
534     if (self->client->state == NULL)
535         Py_RETURN_NONE;
536     
537     ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
538     if (ret == NULL) {
539         PyErr_NoMemory();
540         return NULL;
541     }
542
543     Py_INCREF(self);
544     ret->parent = (PyObject *)self;
545     ret->state = self->client->state;
546
547     return (PyObject *)ret;
548 }
549
550 static PyObject *py_client_get_default_target(PyClientObject *self, void *closure)
551 {
552     return PyString_FromString(client_get_default_target(self->client));
553 }
554
555 static PyObject *py_client_get_own_hostmask(PyClientObject *self, void *closure)
556 {
557     const char *hostmask = client_get_own_hostmask(self->client);
558     if (hostmask == NULL)
559         Py_RETURN_NONE;
560     return PyString_FromString(hostmask);
561 }
562
563 static PyObject *py_client_get_default_origin(PyClientObject *self, void *closure)
564 {
565     return PyString_FromString(self->client->default_origin);
566 }
567
568 static PyObject *py_client_get_last_ping(PyClientObject *self, void *closure)
569 {
570     return PyLong_FromLong(self->client->last_ping);
571 }
572
573 static PyObject *py_client_get_last_pong(PyClientObject *self, void *closure)
574 {
575     return PyLong_FromLong(self->client->last_pong);
576 }
577
578 static PyObject *py_client_get_description(PyClientObject *self, void *closure)
579 {
580     return PyString_FromString(self->client->description);
581 }
582
583 static PyObject *py_client_get_authenticated(PyClientObject *self, void *closure)
584 {
585     return PyBool_FromLong(self->client->authenticated);
586 }
587
588 static PyObject *py_client_get_transport(PyClientObject *self, void *closure)
589 {
590     if (self->client->transport == NULL)
591         Py_RETURN_NONE;
592
593     if (self->client->transport->backend_ops == &py_transport_ops) {
594         PyObject *ret = (PyObject *)self->client->transport->backend_data;
595         Py_INCREF(ret);
596         return ret;
597     } else {
598         PyTransportObject *ret;
599         ret = PyObject_New(PyTransportObject, &PyTransportType);
600         if (ret == NULL) {
601             PyErr_NoMemory();
602             return NULL;
603         }
604
605         Py_INCREF(self);
606         ret->parent = (PyObject *)self;
607         ret->transport = self->client->transport;
608         return (PyObject *)ret;
609     }
610 }
611
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,
625         "Authenticated" },
626     { "transport", (getter)py_client_get_transport, NULL,
627         "Transport" },
628     { NULL }
629 };
630
631 static PyObject *py_client_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
632 {
633     PyClientObject *ret;
634     PyObject *py_transport;
635     struct irc_transport *transport;
636     char *default_origin, *desc;
637     char *kwnames[] = { "transport", "default_origin", "desc", NULL };
638
639     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss", kwnames, &py_transport, &default_origin, &desc))
640         return NULL;
641     
642     ret = (PyClientObject *)type->tp_alloc(type, 0);
643     if (ret == NULL) {
644         PyErr_NoMemory();
645         return NULL;
646     }
647
648     transport = wrap_py_transport(py_transport);
649
650     ret->client = irc_client_new(transport, default_origin, desc, &py_client_callbacks);
651     ret->client->private_data = ret;
652
653     return (PyObject *)ret;
654 }
655
656 PyTypeObject PyClientType = {
657     .tp_name = "Client",
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)
663 };
664
665 static PyObject *py_network_connect(PyNetworkObject *self)
666 {
667     if (!connect_network(self->network)) {
668         PyErr_SetString(PyExc_RuntimeError, "Unable to connect to network");
669         return NULL;
670     }
671
672     Py_RETURN_NONE;
673 }
674
675 static PyObject *py_network_disconnect(PyNetworkObject *self)
676 {
677     disconnect_network(self->network);
678
679     Py_RETURN_NONE;
680 }
681     
682 static PyObject *py_network_send_line(PyNetworkObject *self, PyObject *args)
683 {
684     PyObject *py_line, *py_client = Py_None;
685     struct irc_line *l;
686
687     if (!PyArg_ParseTuple(args, "O|O", &py_line, &py_client))
688         return NULL;
689
690     l = PyObject_AsLine(py_line);
691     if (l == NULL)
692         return NULL;
693
694     if (!network_send_line(self->network, NULL, l)) {
695         PyErr_SetString(PyExc_RuntimeError, "Error sending line to network");
696         free_line(l);
697         return NULL;
698     }
699     free_line(l);
700     Py_RETURN_NONE;
701 }
702
703 static PyObject *py_network_set_charset(PyNetworkObject *self, PyObject *args)
704 {
705     char *name;
706     if (!PyArg_ParseTuple(args, "s", &name))
707         return NULL;
708
709     if (!network_set_charset(self->network, name)) {
710         PyErr_SetString(PyExc_RuntimeError, "Unable to set character set");
711         return NULL;
712     }
713
714     Py_RETURN_NONE;
715 }
716
717 static PyObject *py_network_next_server(PyNetworkObject *self)
718 {
719         irc_network_select_next_server(self->network);
720         Py_RETURN_NONE;
721 }
722
723 static PyObject *py_network_feature_string(PyNetworkObject *self)
724 {
725         char *str = network_generate_feature_string(self->network);
726         PyObject *ret = PyString_FromString(str);
727         g_free(str);
728         return ret;
729 }
730
731 static PyMethodDef py_network_methods[] = {
732     { "connect", (PyCFunction)py_network_connect, METH_NOARGS,
733         NULL },
734     { "disconnect", (PyCFunction)py_network_disconnect, METH_NOARGS,
735         NULL },
736     { "send_line", (PyCFunction)py_network_send_line, METH_VARARGS,
737         NULL },
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." },
744     { NULL }
745 };
746
747 static void py_network_dealloc(PyNetworkObject *self)
748 {
749     irc_network_unref(self->network);
750     PyObject_Del(self);
751 }
752
753 static PyObject *py_network_repr(PyNetworkObject *self)
754 {
755     return PyString_FromFormat("<Network '%s'>", self->network->name);
756 }
757
758 static PyObject *py_network_get_name(PyNetworkObject *self, void *closure)
759 {
760     return PyString_FromString(self->network->name);
761 }
762
763 static PyObject *py_network_get_reconnect_interval(PyNetworkObject *self, void *closure)
764 {
765     return PyInt_FromLong(self->network->reconnect_interval);
766 }   
767
768 static int py_network_set_reconnect_interval(PyNetworkObject *self, PyObject *value, void *closure)
769 {
770     if (!PyInt_Check(value)) {
771         PyErr_SetNone(PyExc_TypeError);
772         return -1;
773     }
774
775     self->network->reconnect_interval = PyInt_AsLong(value);
776     return 0;
777 }
778
779 static PyObject *py_network_get_info(PyNetworkObject *self, void *closure)
780 {
781     PyNetworkInfoObject *pyinfo = PyObject_New(PyNetworkInfoObject, &PyNetworkInfoType);
782
783     if (pyinfo == NULL) {
784         PyErr_NoMemory();
785         return NULL;
786     }
787
788     Py_INCREF(self);
789     pyinfo->parent = (PyObject *)self;
790     pyinfo->info = self->network->info;
791
792     return (PyObject *)pyinfo;
793 }
794
795 static PyObject *py_network_get_internal_state(PyNetworkObject *self, void *closure)
796 {
797     PyNetworkStateObject *ret;
798
799     if (self->network->internal_state == NULL)
800         Py_RETURN_NONE;
801     
802     ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
803     if (ret == NULL) {
804         PyErr_NoMemory();
805         return NULL;
806     }
807
808     Py_INCREF(self);
809     ret->parent = (PyObject *)self;
810     ret->state = self->network->internal_state;
811
812     return (PyObject *)ret;
813 }
814
815 static PyObject *py_network_get_external_state(PyNetworkObject *self, void *closure)
816 {
817     PyNetworkStateObject *ret;
818
819     if (self->network->external_state == NULL)
820         Py_RETURN_NONE;
821     
822     ret = PyObject_New(PyNetworkStateObject, &PyNetworkStateType);
823     if (ret == NULL) {
824         PyErr_NoMemory();
825         return NULL;
826     }
827
828     Py_INCREF(self);
829     ret->parent = (PyObject *)self;
830     ret->state = self->network->external_state;
831
832     return (PyObject *)ret;
833 }
834
835 static PyObject *py_network_get_linestack_errors(PyNetworkObject *self, void *closure)
836 {
837     return PyInt_FromLong(self->network->linestack_errors);
838 }
839
840 static PyObject *PyClientFromPtr(struct irc_client *c)
841 {
842     PyClientObject *ret = PyObject_New(PyClientObject, &PyClientType);
843     if (ret == NULL) {
844         PyErr_NoMemory();
845         return NULL;
846     }
847     
848     ret->client = c;
849     client_ref(c);
850     return (PyObject *)ret;
851 }
852
853 static void *PyPtrFromClient(PyObject *obj)
854 {
855     if (!PyObject_TypeCheck(obj, &PyClientType)) {
856         PyErr_SetNone(PyExc_TypeError);
857         return NULL;
858     }
859
860     return ((PyClientObject *)obj)->client;
861 }   
862
863 static PyObject *py_network_get_query_stack(PyNetworkObject *self, void *closure)
864 {
865     PyQueryStackObject *ret = PyObject_New(PyQueryStackObject, &PyQueryStackType);
866     if (ret == NULL) {
867         PyErr_NoMemory();
868         return NULL;
869     }
870
871     ret->stack = self->network->queries;
872     ret->import_userdata = (PyObject *(*)(void *))PyClientFromPtr;
873     ret->export_userdata = PyPtrFromClient;
874     Py_INCREF(self);
875     ret->parent = (PyObject *)self;
876
877     return (PyObject *)ret;
878 }
879
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" },
888     { NULL }
889 };
890
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,
899 };
900
901 static int py_process_from_client(struct irc_client *client, const struct irc_line *line)
902 {
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);
909     Py_DECREF(py_line);
910     Py_XDECREF(ret);
911     return 0;
912 }
913
914 static void py_log_client(enum log_level level, const struct irc_client *client, const char *text)
915 {
916     PyObject *self, *ret;
917     self = client->private_data;
918     ret = PyObject_CallMethod(self, "log", "is", level, text);
919     if (ret == NULL) {
920         PyErr_Clear(); /* FIXME */
921         return;
922     }
923     Py_DECREF(ret);
924 }
925
926 static int py_process_to_client(struct irc_client *client, const struct irc_line *line)
927 {
928     PyObject *self, *ret;
929     PyLineObject *py_line;
930
931     self = client->private_data;
932     py_line = PyObject_New(PyLineObject, &PyLineType);
933     py_line->line = linedup(line);
934
935     ret = PyObject_CallMethod(self, "process_to_client", "O", py_line);
936     Py_DECREF(py_line);
937     if (ret == NULL) {
938         PyErr_Clear(); /* FIXME: */
939         return -1;
940     }
941     Py_DECREF(ret);
942
943     return 0;
944 }
945
946 static int py_welcome_client(struct irc_client *client)
947 {
948     PyObject *ret, *self;
949     self = client->private_data;
950     ret = PyObject_CallMethod(self, "welcome", "");
951     if (ret == NULL)
952         return false;
953     if (ret == Py_True || ret == Py_None)
954         return true;
955     return false;
956 }
957
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
963 };
964
965 static PyObject *py_query_stack_record(PyQueryStackObject *self, PyObject *args)
966 {
967     PyObject *py_token, *py_line;
968     void *userdata;
969     struct irc_line *line;
970
971     if (!PyArg_ParseTuple(args, "OO", &py_token, &py_line))
972         return NULL;
973
974     line = PyObject_AsLine(py_line);
975     if (line == NULL)
976         return NULL;
977
978     if (self->export_userdata == NULL) {
979         userdata = py_token;
980     } else {
981         userdata = self->export_userdata(py_token);
982         if (userdata == NULL) {
983             free_line(line);
984             return NULL;
985         }
986     }
987     return PyBool_FromLong(query_stack_record(self->stack, userdata, line));
988 }
989
990 static PyObject *py_query_stack_redirect(PyQueryStackObject *self, PyObject *args)
991 {
992     PyObject *py_line;
993     struct irc_line *line;
994     PyObject *ret;
995
996     if (!PyArg_ParseTuple(args, "O", &py_line))
997         return NULL;
998
999     line = PyObject_AsLine(py_line);
1000     if (line == NULL)
1001         return NULL;
1002
1003     ret = (PyObject *)query_stack_match_response(self->stack, line);
1004     if (ret == NULL) {
1005         Py_RETURN_NONE;
1006     } else {
1007         Py_INCREF(ret);
1008         return ret;
1009     }
1010 }
1011
1012 static PyObject *py_query_stack_clear(PyQueryStackObject *self)
1013 {
1014     query_stack_clear(self->stack);
1015     Py_RETURN_NONE;
1016 }
1017
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 },
1022     { NULL }
1023 };
1024
1025 static int py_query_stack_dealloc(PyQueryStackObject *self)
1026 {
1027     if (self->parent != NULL) {
1028         Py_DECREF(self->parent);
1029     } else {
1030         query_stack_free(self->stack);
1031     }
1032     PyObject_Del(self);
1033     return 0;
1034 }
1035
1036 static PyObject *Py_Id(void *obj)
1037 {
1038     return obj;
1039 }
1040
1041 static PyObject *py_query_stack_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1042 {
1043     PyQueryStackObject *self = (PyQueryStackObject *)type->tp_alloc(type, 0);
1044     if (self == NULL) {
1045         PyErr_NoMemory();
1046         return NULL;
1047     }
1048
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;
1053
1054     return (PyObject *)self;
1055 }
1056
1057 static PyObject *py_query_stack_entry_from_ptr(PyQueryStackObject *parent, struct query_stack_entry *e)
1058 {
1059     return Py_BuildValue("(O&sl)", parent->import_userdata, e->userdata, e->query->name, e->time);
1060 }
1061
1062 static PyObject *py_query_stack_iter(PyQueryStackObject *self)
1063 {
1064     return py_g_list_iter(self->stack->entries, (PyObject *)self, (PyObject *(*)(PyObject *, void*))py_query_stack_entry_from_ptr);
1065 }
1066
1067 static Py_ssize_t py_query_stack_len(PyQueryStackObject *self)
1068 {
1069     return g_list_length(self->stack->entries);
1070 }
1071
1072 static PySequenceMethods py_query_stack_sequence = {
1073     .sq_length = (lenfunc)py_query_stack_len,
1074 };
1075
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,
1085 };
1086
1087
1088 static PyMethodDef irc_methods[] = { 
1089     { NULL }
1090 };
1091
1092 void initirc(void)
1093 {
1094     PyObject *m;
1095
1096     if (PyType_Ready(&PyLineType) < 0)
1097         return;
1098
1099     if (PyType_Ready(&PyClientType) < 0)
1100         return;
1101
1102     if (PyType_Ready(&PyNetworkInfoType) < 0)
1103         return;
1104
1105     if (PyType_Ready(&PyNetworkStateType) < 0)
1106         return;
1107
1108     if (PyType_Ready(&PyNetworkType) < 0)
1109         return;
1110
1111     if (PyType_Ready(&PyChannelStateType) < 0)
1112         return;
1113
1114     if (PyType_Ready(&PyNetworkNickType) < 0)
1115         return;
1116
1117     if (PyType_Ready(&PyChannelModeDictType) < 0)
1118         return;
1119
1120     if (PyType_Ready(&PyNetworkChannelDictType) < 0)
1121         return;
1122
1123     if (PyType_Ready(&PyGListIterType) < 0)
1124         return;
1125
1126     if (PyType_Ready(&PyQueryStackType) < 0)
1127         return;
1128
1129     if (PyType_Ready(&PyTransportType) < 0)
1130         return;
1131
1132     if (PyType_Ready(&PyLinestackType) < 0)
1133         return;
1134
1135     if (PyType_Ready(&PyChannelModeDictType) < 0)
1136         return;
1137
1138     if (PyType_Ready(&PyChannelNickDictType) < 0)
1139         return;
1140
1141     m = Py_InitModule3("irc", irc_methods, 
1142                        "Simple IRC protocol module for Python.");
1143     if (m == NULL)
1144         return;
1145
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);
1168 }
1169