WIP: pth transistion, 3rd step, commands basically ported
[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 struct rxpd_connection*
25 rxpd_connection_cmd_CHECK (struct rxpd_connection* self)
26 {
27   char* line;
28
29   while ((line = rxpd_buffer_readline (&self->in)))
30     {
31       if (*line == '\0')
32         {
33           rxpd_buffer_printf (&self->out, "#OK:\n");
34         }
35       else
36         {
37           LLIST_FOREACH (&self->file->rules, n)
38             {
39               struct rxpd_rule* rule = (struct rxpd_rule*)n;
40               if (rule->string[0] != '#')
41                 {
42                   if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
43                     {
44                       if (rule->atime != (time_t) -1)
45                         time (&rule->atime);
46
47                       rxpd_buffer_printf (&self->out, "%s\n", rule->string);
48                       break;
49                     }
50                 }
51             }
52         }
53     }
54 #if 0
55   else if (!self->file)
56     {
57       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
58       rxpd_connection_delete (self);
59       return;
60     }
61   if (rxpd_buffer_state (&self->in) == RXPD_OK)
62     rxpd_connection_schedule (self);
63   else
64     {
65       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
66         rxpd_buffer_printf (&self->out, "#ERROR:\n");
67       rxpd_connection_delete (self);
68     }
69 #endif
70
71   return self;
72 }
73
74
75
76 static void
77 rxpd_connection_APPEND_PREPEND_helper (struct rxpd_connection* self)
78 {
79   char* line;
80
81   while ((line = rxpd_buffer_readline (&self->in)))
82     {
83       if (*line)
84         {
85           struct rxpd_rule* rule;
86           rule = rxpd_rule_new (line);
87           if (!rule)
88             abort();
89
90           llist_insert_tail (&self->tmp_list, &rule->node);
91         }
92       //          else goto finish;     /* move along, look elsewhere! This goto is not harmful and saves some code. */
93     }
94
95 #if 0
96   else if (!event && !self->file)
97     {
98       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
99       rxpd_connection_delete (self);
100       return;
101     }
102
103   if (rxpd_buffer_state (&self->in) == RXPD_OK)
104     rxpd_connection_schedule (self);
105   else
106     {
107       // TODO should also print error when any rule compilation failed, use tmp_str to save case?
108       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
109         rxpd_buffer_printf (&self->out, "#ERROR:\n");
110       else
111         {
112         finish:
113           rxpd_buffer_printf (&self->out, "#OK:\n");
114         }
115
116       rxpd_connection_delete (self);
117     }
118 #endif
119 }
120
121 struct rxpd_connection*
122 rxpd_connection_cmd_APPEND (struct rxpd_connection* self)
123 {
124   rxpd_connection_APPEND_PREPEND_helper (self);
125   llist_insertlist_prev (&self->file->rules, &self->tmp_list);
126   return self;
127 }
128
129 struct rxpd_connection*
130 rxpd_connection_cmd_PREPEND (struct rxpd_connection* self)
131 {
132   rxpd_connection_APPEND_PREPEND_helper (self);
133   llist_insertlist_next (&self->file->rules, &self->tmp_list);
134   return self;
135 }
136
137
138 struct rxpd_connection*
139 rxpd_connection_cmd_REMOVE (struct rxpd_connection* self)
140 {
141   char* line;
142   while ((line = rxpd_buffer_readline (&self->in)))
143     {
144       LLIST_FOREACH (&self->file->rules, n)
145         {
146           struct rxpd_rule* rule = (struct rxpd_rule*)n;
147           if (strcmp (rule->string, line) == 0)
148             {
149               LList tmp = llist_prev (n);
150               rxpd_rule_delete (rule);
151               n = tmp;
152               rxpd_buffer_printf (&self->out, "#OK:\n");
153               goto done;
154             }
155         }
156       rxpd_buffer_printf (&self->out, "#ERROR: line not found\n");
157     done:
158       ;
159     }
160
161 #if 0
162   else if (!self->file)
163     {
164       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
165       rxpd_connection_delete (self);
166       return;
167     }
168
169   if (rxpd_buffer_state (&self->in) == RXPD_OK)
170     rxpd_connection_schedule (self);
171   else
172     {
173       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
174         rxpd_buffer_printf (&self->out, "#ERROR:\n");
175       rxpd_connection_delete (self);
176     }
177 #endif
178   return self;
179 }
180
181
182 static int
183 rxpd_connection_do_REPLACE (struct rxpd_connection* self)
184 {
185   struct rxpd_rule* rule;
186
187   LLIST_FOREACH (&self->file->rules, n)
188     {
189       rule = (struct rxpd_rule*)n;
190       if (strcmp (rule->string, self->tmp_str) == 0)
191         goto found;
192     }
193   return 0;
194  found:
195   llist_insertlist_next (&rule->node, &self->tmp_list);
196   rxpd_rule_delete (rule);
197   free (self->tmp_str);
198   self->tmp_str = NULL;
199   return 1;
200 }
201
202 struct rxpd_connection*
203 rxpd_connection_cmd_REPLACE (struct rxpd_connection* self)
204 {
205   char* line;
206   while ((line = rxpd_buffer_readline (&self->in)))
207     {
208       if (self->tmp_str)
209         {
210           if (*line)
211             {
212               struct rxpd_rule* rule;
213               rule = rxpd_rule_new (line);
214               if (!rule)
215                 abort();
216
217               llist_insert_tail (&self->tmp_list, &rule->node);
218             }
219           /* TODO handle empty lines? */
220         }
221       else
222         self->tmp_str = rxpd_strdup (line);
223     }
224
225 #if 0
226   else if (!self->file)
227     {
228       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
229       rxpd_connection_delete (self);
230       return;
231     }
232
233   if (rxpd_buffer_state (&self->in) == RXPD_OK)
234     rxpd_connection_schedule (self);
235   else
236     {
237       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
238         rxpd_buffer_printf (&self->out, "#ERROR:\n");
239       else
240         {
241         }
242
243       rxpd_connection_delete (self);
244     }
245 #endif
246   if (rxpd_connection_do_REPLACE (self))
247     rxpd_buffer_printf (&self->out, "#OK:\n");
248   else
249     rxpd_buffer_printf (&self->out, "#ERROR: rule matching '%s'\n", self->tmp_str);
250   return self;
251 }
252
253 struct rxpd_connection*
254 rxpd_connection_cmd_LOAD (struct rxpd_connection* self)
255 {
256   if (self->file)
257     {
258       if (rxpd_file_load (self->file))
259         {
260           rxpd_buffer_printf (&self->out, "#OK:\n");
261         }
262       else
263         {
264           rxpd_buffer_printf (&self->out, "#ERROR: loading file '%s'\n", (const char*)self->file->node.key);
265         }
266     }
267   else
268     rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
269   return self;
270 }
271
272 struct rxpd_connection*
273 rxpd_connection_cmd_SAVE (struct rxpd_connection* self)
274 {
275   if (self->file)
276     {
277       if (rxpd_file_save (self->file))
278         {
279           rxpd_buffer_printf (&self->out, "#OK:\n");
280         }
281       else
282         {
283           rxpd_buffer_printf (&self->out, "#ERROR: saving file '%s'\n", (const char*)self->file->node.key);
284         }
285     }
286   else
287     rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
288   return self;
289 }
290
291 struct rxpd_connection*
292 rxpd_connection_cmd_DELETE (struct rxpd_connection* self)
293 {
294   if (self->file)
295     {
296       rxpd_file_delete (self->file);
297       rxpd_buffer_printf (&self->out, "#OK:\n");
298     }
299   return self;
300 }
301
302 struct rxpd_connection*
303 rxpd_connection_cmd_FETCH (struct rxpd_connection* self)
304 {
305   struct rxpd_base* base = self->socket->base;
306
307   char* line;
308   line = rxpd_buffer_readline (&self->in);
309   if (*line)
310     {
311       rxpd_file_rules_delete (self->file);
312
313       char* list = strrchr (line, '/');
314       // TODO error handling
315       if (!list)
316         rxpd_die ("syntax error");
317
318       *list = '\0';
319       ++ list;
320
321       char* port = strrchr (line, ':');
322       // TODO error handling / unix domain sockets
323       if (!port)
324         rxpd_die ("syntax error");
325
326       *port = '\0';
327       ++ port;
328
329       struct addrinfo* addrs = NULL;
330       int aierr;
331
332       aierr = getaddrinfo (line, port, NULL, &addrs);
333
334       rxpd_log (base, LOG_INFO, "fetching list '%s' from '%s(%s)' at port '%s' to '%s'\n",
335                 list,
336                 line,
337                 inet_ntoa (((struct sockaddr_in*)addrs->ai_addr)->sin_addr),
338                 port,
339                 self->file->node.key);
340
341       if (aierr)
342         rxpd_die ("resolv error %s\n", gai_strerror (aierr));
343
344       // connect
345       // send dump
346       // add recieving event
347
348       freeaddrinfo (addrs);
349     }
350
351
352 #if 0
353   else if (!self->file)
354     {
355       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
356       rxpd_connection_delete (self);
357       return;
358     }
359
360   if (!event && rxpd_buffer_state (&self->in) == RXPD_OK)
361     rxpd_connection_schedule (self);
362 #endif
363   return self;
364 }
365
366 struct rxpd_connection*
367 rxpd_connection_cmd_DUMP (struct rxpd_connection* self)
368 {
369 #if 0
370   if (!event && !self->file)
371     {
372       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
373       rxpd_connection_delete (self);
374       return;
375     }
376 #endif
377
378   if (llist_is_empty (&self->file->rules))
379     rxpd_buffer_printf (&self->out, "#OK:\n");
380   else
381     {
382       LLIST_FOREACH (&self->file->rules, n)
383         {
384           struct rxpd_rule* rule = (struct rxpd_rule*)n;
385           if (rule->atime != (time_t)-1)
386             rxpd_buffer_printf (&self->out, "%ld:%s\n", rule->atime, rule->string);
387           else if (*rule->string != '#')
388             rxpd_buffer_printf (&self->out, ":%s\n", rule->string);
389           else
390             rxpd_buffer_printf (&self->out, "%s\n", rule->string);
391         }
392     }
393   return self;
394 }
395
396
397 static psplay_delete_t
398 walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
399 {
400   (void) level;
401   struct rxpd_file* file = (struct rxpd_file*) node;
402   struct rxpd_connection* conn = (struct rxpd_connection*) data;
403
404   if (which == PSPLAY_INORDER)
405     rxpd_buffer_printf (&conn->out, "%s\n", file->node.key);
406
407   return PSPLAY_CONT;
408 }
409
410
411 struct rxpd_connection*
412 rxpd_connection_cmd_LIST (struct rxpd_connection* self)
413 {
414   struct rxpd_base* base = self->socket->base;
415
416   if (psplay_isempty_root (&base->files))
417     rxpd_buffer_printf (&self->out, "#OK:\n");
418   else
419     psplay_walk (&base->files, NULL, walk_LIST, 0, self);
420   return self;
421 }
422
423 struct rxpd_connection*
424 rxpd_connection_cmd_SHUTDOWN (struct rxpd_connection* self)
425 {
426   //struct rxpd_base* base = self->socket->base;
427   // destroy all sockets
428 #if 0
429   LLIST_WHILE_HEAD (&base->sockets, n)
430     {
431       struct rxpd_socket* socket = (struct rxpd_socket*)n;
432       rxpd_socket_delete (socket);
433     }
434   rxpd_buffer_printf (&self->out, "#OK:\n");
435 #endif
436   return self;
437 }
438
439
440 struct rxpd_connection*
441 rxpd_connection_cmd_VERSION (struct rxpd_connection* self)
442 {
443   rxpd_buffer_printf (&self->out, PACKAGE_STRING "\n#\n"
444                       "# Copyright (C)\n"
445                       "#   2007,               Christian Thaeter <ct@pipapo.org>\n#\n"
446                       "# This is free software.  You may redistribute copies of it under the terms of\n"
447                       "# the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
448                       "# There is NO WARRANTY, to the extent permitted by law.\n#\n"
449                       "# http://www.pipapo.org/pipawiki/RegexPolicyDaemon\n");
450   return self;
451 }
452
453 struct rxpd_connection*
454 rxpd_connection_cmd_HELP (struct rxpd_connection* self)
455 {
456   //struct rxpd_base* base = self->socket->base;
457   rxpd_buffer_printf (&self->out, "# Available commands:\n#\n");
458 #define RXPD_CMD(cmd, help)     rxpd_buffer_printf (&self->out, "# %s %s.\n", #cmd, help);
459   RXPD_COMMANDS
460 #undef RXPD_CMD
461   rxpd_buffer_printf (&self->out, "#\n# general syntax is: 'COMMAND:listname\\n..data..'\n");
462   return self;
463 }
464
465 struct rxpd_connection*
466 rxpd_connection_cmd_EXPIRE (struct rxpd_connection* self)
467 {
468   struct rxpd_base* base = self->socket->base;
469
470   char* line;
471   while ((line = rxpd_buffer_readline (&self->in)))
472     {
473       if (*line)
474         {
475           time_t since = time (NULL) - atoi (line);
476           rxpd_log (base, LOG_INFO, "expire all entries in '%s' since %ld\n",
477                     (const char*) self->file->node.key, since);
478
479           LLIST_FOREACH (&self->file->rules, n)
480             {
481               struct rxpd_rule* rule = (struct rxpd_rule*)n;
482               if (rule->atime != -1 && rule->atime < since)
483                 {
484                   n = llist_prev (n);
485                   rxpd_log (base, LOG_DEBUG, "expiring %ld:%s\n", rule->atime, rule->string);
486                   rxpd_buffer_printf (&self->out, "#OK: expiring '%s'\n", rule->string);
487                   rxpd_rule_delete (rule);
488                 }
489             }
490         }
491       else
492         rxpd_buffer_printf (&self->out, "#OK:\n");
493     }
494
495
496 #if 0
497     }
498   else if (!self->file)
499     {
500       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
501       rxpd_connection_delete (self);
502       return;
503     }
504
505   if (rxpd_buffer_state (&self->in) == RXPD_OK)
506     rxpd_connection_schedule (self);
507   else
508     {
509       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
510         rxpd_buffer_printf (&self->out, "#ERROR:\n");
511       rxpd_connection_delete (self);
512     }
513 #endif
514   return self;
515 }
516
517 /* Template
518 struct rxpd_connection*
519 rxpd_connection_cmd_ (struct rxpd_connection* ptr)
520 {
521   (void) fd;
522   (void) event;
523   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
524   struct rxpd_base* base = self->socket->base;
525   rxpd_die ("Unimplemented\n");
526 }
527 */