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