Make truncate argument to Linestack optional.
[jelmer/ctrlproxy.git] / libirc / python / linestack.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 static int py_linestack_dealloc(PyLinestackObject *self)
26 {
27     if (self->parent != NULL)
28         Py_DECREF(self->parent);
29     else
30         free_linestack_context(self->linestack);
31     PyObject_Del((PyObject *)self);
32     return 0;
33 }
34
35 static PyObject *py_linestack_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
36 {
37     char *kwnames[] = { "path", "state", "truncate", NULL };
38     PyLinestackObject *self;
39         char *data_dir;
40         int truncate = FALSE;
41         PyObject *py_state;
42     struct irc_network_state *state;
43     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwnames, 
44                                      &data_dir, &py_state, &truncate))
45         return NULL;
46
47     self = (PyLinestackObject *)type->tp_alloc(type, 0);
48     if (self == NULL) {
49         PyErr_NoMemory();
50         return NULL;
51     }
52
53     state = PyObject_AsNetworkState(py_state);
54     if (state == NULL) {
55         return NULL;
56     }
57
58     self->parent = NULL;
59     self->linestack = create_linestack(data_dir, truncate, state);
60
61     return (PyObject *)self;
62 }
63
64 static PyObject *py_linestack_insert_line(PyLinestackObject *self, PyObject *args)
65 {
66     struct irc_line *l;
67     gboolean ret;
68         enum data_direction dir;
69         PyObject *py_line, *py_state;
70         struct irc_network_state *state;
71
72         if (!PyArg_ParseTuple(args, "OiO", &py_line, &dir, &py_state))
73                 return NULL;
74
75     l = PyObject_AsLine(py_line);
76     if (l == NULL) {
77         return NULL;
78     }
79
80     state = PyObject_AsNetworkState(py_state);
81     if (state == NULL) {
82         return NULL;
83     }
84
85     ret = linestack_insert_line(self->linestack, l, dir, state);
86     free_line(l);
87
88     if (!ret) {
89         PyErr_SetNone(PyExc_RuntimeError);
90         return NULL;
91     }
92
93     Py_RETURN_NONE;
94 }
95
96 static PyObject *py_linestack_replay(PyLinestackObject *self, PyObject *args)
97 {
98     guint64 from, to;
99     PyObject *py_state;
100     gboolean ret;
101     struct irc_network_state *state;
102     if (!PyArg_ParseTuple(args, "OLL", &py_state, &from, &to))
103         return NULL;
104
105     state = PyObject_AsNetworkState(py_state);
106     if (state == NULL) {
107         return NULL;
108     }
109
110     ret = linestack_replay(self->linestack, &from, &to, state);
111     if (ret == FALSE) {
112         PyErr_SetNone(PyExc_RuntimeError);
113         return NULL;
114     }
115
116     Py_RETURN_NONE;
117 }
118
119 static PyObject *py_linestack_get_marker(PyLinestackObject *self)
120 {
121     linestack_marker m = linestack_get_marker(self->linestack);
122     if (m == NULL) {
123         PyErr_SetNone(PyExc_RuntimeError);
124         return NULL;
125     }
126     return PyLong_FromLong(*m);
127 }
128
129 static PyObject *py_linestack_send(PyLinestackObject *self, PyObject *args)
130 {
131     int time_offset = 0;
132     gboolean dataonly = FALSE;
133     gboolean timed = FALSE;
134     guint64 from, to;
135     PyObject *py_client;
136     struct irc_client *client;
137     gboolean ret;
138     char *object = NULL;
139
140     if (!PyArg_ParseTuple(args, "LLO|ziii", &from, &to, &py_client,
141                           &object, &dataonly, &timed, &time_offset))
142         return NULL;
143
144     client = PyObject_AsClient(py_client);
145     if (client == NULL) {
146         return NULL;
147     }
148
149     if (object != NULL) {
150         ret = linestack_send_object(self->linestack, object, &from, &to, client,
151                                     dataonly, timed, time_offset);
152     } else {
153         ret = linestack_send(self->linestack, &from, &to, client, dataonly, 
154                              timed, time_offset);
155     }
156     if (!ret) {
157         PyErr_SetNone(PyExc_RuntimeError);
158         return NULL;
159     }
160
161     Py_RETURN_NONE;
162 }
163
164 typedef struct {
165     PyObject_HEAD
166     PyLinestackObject *parent;
167     guint64 from, to;
168 } PyLinestackIterObject;
169
170 static int py_linestack_iter_dealloc(PyLinestackIterObject *self)
171 {
172     Py_DECREF(self->parent);
173     PyObject_Del(self);
174     return 0;
175 }
176
177 static PyObject *py_linestack_iter_next(PyLinestackIterObject *self)
178 {
179     time_t time;
180     struct irc_line *line = NULL;
181     gboolean ret;
182     PyLineObject *py_line;
183     PyObject *py_ret;
184     if (self->from == self->to) {
185         PyErr_SetNone(PyExc_StopIteration);
186         return NULL;
187     }
188
189     ret = linestack_read_entry(self->parent->linestack, self->from, 
190                          &line, &time);
191     if (ret == FALSE) {
192         PyErr_SetNone(PyExc_RuntimeError);
193         return NULL;
194     }
195
196     py_line = PyObject_New(PyLineObject, &PyLineType);
197     py_line->line = line;
198
199     py_ret = Py_BuildValue("(Nl)", py_line, time);
200
201     self->from++;
202     return py_ret;
203 }
204
205 PyTypeObject PyLinestackIterType = {
206     .tp_name = "LinestackIter",
207     .tp_flags = Py_TPFLAGS_DEFAULT,
208     .tp_basicsize = sizeof(PyLinestackIterObject),
209     .tp_iter = PyObject_SelfIter,
210     .tp_iternext = (iternextfunc)py_linestack_iter_next,
211     .tp_dealloc = (destructor)py_linestack_iter_dealloc,
212 };
213
214 static PyObject *py_linestack_traverse(PyLinestackObject *self, PyObject *args)
215 {
216     PyLinestackIterObject *ret;
217     ret = PyObject_New(PyLinestackIterObject, &PyLinestackIterType);
218     if (ret == NULL) {
219         PyErr_NoMemory();
220         return NULL;
221     }
222
223     Py_INCREF(self);
224     ret->parent = self;
225
226     if (!PyArg_ParseTuple(args, "LL", &ret->from, &ret->to)) {
227         Py_DECREF(ret);
228         return NULL;
229     }
230
231     return (PyObject *)ret;
232 }
233
234 static PyMethodDef py_linestack_methods[] = {
235     { "insert_line", (PyCFunction)py_linestack_insert_line, 
236         METH_VARARGS, "Insert line" },
237     { "replay", (PyCFunction)py_linestack_replay,
238         METH_VARARGS, "Replay" },
239     { "get_marker", (PyCFunction)py_linestack_get_marker,
240         METH_NOARGS, "Get marker" },
241     { "send", (PyCFunction)py_linestack_send, METH_VARARGS, 
242         "Send" },
243     { "traverse", (PyCFunction)py_linestack_traverse, METH_VARARGS,
244         "Traverse" },
245     { NULL }
246 };
247
248 PyTypeObject PyLinestackType = {
249     .tp_name = "Linestack",
250     .tp_flags = Py_TPFLAGS_DEFAULT,
251     .tp_new = py_linestack_new,
252     .tp_methods = py_linestack_methods,
253     .tp_basicsize = sizeof(PyLinestackObject),
254     .tp_dealloc = (destructor)py_linestack_dealloc,
255 };