change -D debug verbosity to LOG_INFO
[rxpd] / src / rxpd_connection_cmd.c
1 /*
2     rxpd_connection_cmd.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 void
25 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
26 {
27   (void) fd;
28   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
29
30   if (event == EV_READ)
31     {
32       int again = -1;
33       char* line;
34       while ((line = rxpd_buffer_readline (&self->in, ++again)))
35         {
36           if (*line == '\0')
37             {
38               rxpd_buffer_printf (&self->out, "#OK:\n");
39             }
40           else
41             {
42               LLIST_FOREACH (&self->file->rules, n)
43                 {
44                   struct rxpd_rule* rule = (struct rxpd_rule*)n;
45                   if (rule->string[0] != '#')
46                     {
47                       if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
48                         {
49                           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
50                           break;
51                         }
52                     }
53                 }
54             }
55         }
56     }
57   else if (!self->file)
58     {
59       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
60       rxpd_connection_delete (self);
61       return;
62     }
63
64   if (rxpd_buffer_state (&self->in) == RXPD_OK)
65     rxpd_connection_schedule (self);
66   else
67     {
68       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
69         rxpd_buffer_printf (&self->out, "#ERROR:\n");
70       rxpd_connection_delete (self);
71     }
72 }
73
74
75
76 static void
77 rxpd_connection_APPEND_PREPEND_helper (short event, void* ptr, int do_append)
78 {
79   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
80
81   if (event == EV_READ)
82     {
83       int again = -1;
84       char* line;
85
86       while ((line = rxpd_buffer_readline (&self->in, ++again)))
87         {
88           if (*line)
89             {
90               struct rxpd_rule* rule;
91               rule = rxpd_rule_new (line);
92               if (!rule)
93                 abort();
94
95               llist_insert_tail (&self->tmp_list, &rule->node);
96             }
97           else goto finish;     /* move along, look elsewhere! This goto is not harmful and saves some code. */
98         }
99     }
100   else if (!event && !self->file)
101     {
102       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
103       rxpd_connection_delete (self);
104       return;
105     }
106
107   if (rxpd_buffer_state (&self->in) == RXPD_OK)
108     rxpd_connection_schedule (self);
109   else
110     {
111       // TODO should also print error when any rule compilation failed, use tmp_str to save case?
112       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
113         rxpd_buffer_printf (&self->out, "#ERROR:\n");
114       else
115         {
116         finish:
117           rxpd_buffer_printf (&self->out, "#OK:\n");
118         }
119
120       if (do_append)
121         llist_insertlist_prev (&self->file->rules, &self->tmp_list);
122       else
123         llist_insertlist_next (&self->file->rules, &self->tmp_list);
124       rxpd_connection_delete (self);
125     }
126 }
127
128 void
129 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
130 {
131   (void) fd;
132   rxpd_connection_APPEND_PREPEND_helper (event, ptr, 1);
133 }
134
135 void
136 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
137 {
138   (void) fd;
139   rxpd_connection_APPEND_PREPEND_helper (event, ptr, 0);
140 }
141
142
143 void
144 rxpd_connection_cmd_REMOVE (int fd, short event, void* ptr)
145 {
146   (void) fd;
147   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
148
149   if (event == EV_READ)
150     {
151       int again = -1;
152       char* line;
153       while ((line = rxpd_buffer_readline (&self->in, ++again)))
154         {
155           LLIST_FOREACH (&self->file->rules, n)
156             {
157               struct rxpd_rule* rule = (struct rxpd_rule*)n;
158               if (strcmp (rule->string, line) == 0)
159                 {
160                   LList tmp = llist_prev (n);
161                   rxpd_rule_delete (rule);
162                   n = tmp;
163                   rxpd_buffer_printf (&self->out, "#OK:\n");
164                   goto done;
165                 }
166             }
167           rxpd_buffer_printf (&self->out, "#ERROR: line not found\n");
168         done:
169           ;
170         }
171     }
172   else if (!self->file)
173     {
174       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
175       rxpd_connection_delete (self);
176       return;
177     }
178
179   if (rxpd_buffer_state (&self->in) == RXPD_OK)
180     rxpd_connection_schedule (self);
181   else
182     {
183       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
184         rxpd_buffer_printf (&self->out, "#ERROR:\n");
185       rxpd_connection_delete (self);
186     }
187 }
188
189
190 static int
191 rxpd_connection_do_REPLACE (struct rxpd_connection* self)
192 {
193   struct rxpd_rule* rule;
194
195   LLIST_FOREACH (&self->file->rules, n)
196     {
197       rule = (struct rxpd_rule*)n;
198       if (strcmp (rule->string, self->tmp_str) == 0)
199         goto found;
200     }
201   return 0;
202  found:
203   llist_insertlist_next (&rule->node, &self->tmp_list);
204   rxpd_rule_delete (rule);
205   free (self->tmp_str);
206   self->tmp_str = NULL;
207   return 1;
208 }
209
210 void
211 rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
212 {
213   (void) fd;
214   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
215
216   if (event == EV_READ)
217     {
218       int again = -1;
219       char* line;
220       while ((line = rxpd_buffer_readline (&self->in, ++again)))
221         {
222           if (self->tmp_str)
223             {
224               if (*line)
225                 {
226                   struct rxpd_rule* rule;
227                   rule = rxpd_rule_new (line);
228                   if (!rule)
229                     abort();
230
231                   llist_insert_tail (&self->tmp_list, &rule->node);
232                 }
233               /* TODO handle empty lines? */
234             }
235           else
236             self->tmp_str = rxpd_strdup (line);
237         }
238     }
239   else if (!self->file)
240     {
241       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
242       rxpd_connection_delete (self);
243       return;
244     }
245
246   if (rxpd_buffer_state (&self->in) == RXPD_OK)
247     rxpd_connection_schedule (self);
248   else
249     {
250       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
251         rxpd_buffer_printf (&self->out, "#ERROR:\n");
252       else
253         {
254           if (rxpd_connection_do_REPLACE (self))
255             rxpd_buffer_printf (&self->out, "#OK:\n");
256           else
257             rxpd_buffer_printf (&self->out, "#ERROR: rule matching '%s'\n", self->tmp_str);
258         }
259
260       rxpd_connection_delete (self);
261     }
262 }
263
264 void
265 rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
266 {
267   (void) fd;
268   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
269
270   if (!event)
271     {
272       if (self->file)
273         {
274           if (rxpd_file_load (self->file))
275             {
276               rxpd_buffer_printf (&self->out, "#OK:\n");
277             }
278           else
279             {
280               rxpd_buffer_printf (&self->out, "#ERROR: loading file '%s'\n", (const char*)self->file->node.key);
281             }
282         }
283       else
284         rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
285       rxpd_connection_delete (self);
286     }
287 }
288
289 void
290 rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
291 {
292   (void) fd;
293   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
294
295   if (!event)
296     {
297       if (self->file)
298         {
299           if (rxpd_file_save (self->file))
300             {
301               rxpd_buffer_printf (&self->out, "#OK:\n");
302             }
303           else
304             {
305               rxpd_buffer_printf (&self->out, "#ERROR: saving file '%s'\n", (const char*)self->file->node.key);
306             }
307         }
308       else
309         rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
310       rxpd_connection_delete (self);
311     }
312 }
313
314 void
315 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
316 {
317   (void) fd;
318   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
319
320   if (!event && !self->file)
321     {
322       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
323       rxpd_connection_delete (self);
324       return;
325     }
326
327   if (llist_is_empty (&self->file->rules))
328     rxpd_buffer_printf (&self->out, "#OK:\n");
329   else
330     {
331       LLIST_FOREACH (&self->file->rules, n)
332         {
333           struct rxpd_rule* rule = (struct rxpd_rule*)n;
334           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
335         }
336     }
337
338   rxpd_connection_delete (self);
339 }
340
341
342 static psplay_delete_t
343 walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
344 {
345   (void) level;
346   struct rxpd_file* file = (struct rxpd_file*) node;
347   struct rxpd_connection* conn = (struct rxpd_connection*) data;
348
349   if (which == PSPLAY_INORDER)
350     rxpd_buffer_printf (&conn->out, "%s\n", file->node.key);
351
352   return PSPLAY_CONT;
353 }
354
355
356 void
357 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
358 {
359   (void) fd;
360   (void) event;
361   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
362   struct rxpd_base* base = self->socket->base;
363
364   if (psplay_isempty_root (&base->files))
365     rxpd_buffer_printf (&self->out, "#OK:\n");
366   else
367     psplay_walk (&base->files, NULL, walk_LIST, 0, ptr);
368
369   rxpd_connection_delete (self);
370 }
371
372 void
373 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
374 {
375   (void) fd;
376   (void) event;
377   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
378   struct rxpd_base* base = self->socket->base;
379   // destroy all sockets
380   LLIST_WHILE_HEAD (&base->sockets, n)
381     {
382       struct rxpd_socket* socket = (struct rxpd_socket*)n;
383       rxpd_socket_delete (socket);
384     }
385   rxpd_buffer_printf (&self->out, "#OK:\n");
386   rxpd_connection_delete (self);
387 }