7688c8bbc4d4b4a88e82135b417a36f40b81dd2c
[rxpd] / src / rxpd.c
1 /*
2     rxpd.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 static struct rxpd_base global_base;
25
26 struct rxpd_base*
27 rxpd_init (struct event_base* eventbase)
28 {
29   if (global_base.basedir)
30     return NULL;
31
32   global_base.basedir = NULL;
33
34   global_base.verbosity = LOG_WARNING;
35   global_base.daemonize = 0;
36   global_base.regflags = 0;
37   global_base.policy = NULL;
38
39   if (!eventbase)
40     rxpd_die ("no eventbase provided");
41
42   global_base.eventbase = eventbase;
43
44   psplay_init_root (&global_base.files, rxpd_file_cmp, rxpd_file_delete);
45   llist_init (&global_base.sockets);
46
47   rxpd_log (&global_base, LOG_DEBUG, PACKAGE_NAME" initialized\n");
48   return &global_base;
49 }
50
51
52 void
53 rxpd_destroy (void)
54 {
55   if (global_base.basedir)
56     {
57       free (global_base.basedir);
58       psplay_destroy_root (&global_base.files);
59       LLIST_WHILE_HEAD (&global_base.sockets, n)
60         {
61           struct rxpd_socket* socket = (struct rxpd_socket*)n;
62           rxpd_socket_delete (socket);
63         }
64     }
65 }
66
67 void
68 rxpd_log (struct rxpd_base* self, int level, const char* fmt, ...)
69 {
70   va_list ap;
71   va_start (ap, fmt);
72   if (level <= (self?self->verbosity:LOG_DEBUG))
73     {
74       if (!self || self->daemonize)
75         vsyslog (level, fmt, ap);
76       vfprintf (stderr, fmt, ap);
77     }
78   va_end (ap);
79 }
80
81 void
82 rxpd_die (const char* fmt, ...)
83 {
84   va_list ap;
85   va_start(ap, fmt);
86   vsyslog (LOG_EMERG, fmt, ap);
87   vfprintf (stderr, fmt, ap);
88   va_end (ap);
89   abort ();
90 }
91
92 void*
93 rxpd_malloc (size_t size)
94 {
95   void* r;
96   r = malloc (size);
97   if (!r)
98     rxpd_die ("Out of Memeory\n");
99   return r;
100 }
101
102 char*
103 rxpd_strdup (const char* str)
104 {
105   char* r;
106   r = strdup (str);
107   if (!r)
108     rxpd_die ("Out of Memeory\n");
109   return r;
110 }
111
112 //
113 struct rxpd_rule*
114 rxpd_rule_new (const char* buf)
115 {
116   struct rxpd_rule* self = rxpd_malloc (sizeof (struct rxpd_rule));
117
118   llist_init (&self->node);
119
120   if (*buf != '#')
121     {
122       int err;
123       char* rxstart = strchr (buf, ':');
124
125       if (!rxstart)
126         self->string = rxpd_strdup ("#ERROR: Syntax error, line was neither a comment nor a rule");
127       else
128         {
129           // TODO regflags from base
130           err = regcomp (&self->rx, rxstart+1, REG_EXTENDED|REG_ICASE|REG_NOSUB);
131
132           if (!err)
133             self->string = rxpd_strdup (buf);
134           else
135             {
136               regfree (&self->rx);
137               char ebuf[256];
138               size_t len = regerror (err, NULL, ebuf, 256);
139               self->string = rxpd_malloc (len + strlen(buf) + 14);
140               strcpy (self->string, "#ERROR: ");
141               strcat (self->string, ebuf);
142               strcat (self->string, " in '");
143               strcat (self->string, buf);
144               strcat (self->string, "'");
145             }
146         }
147     }
148   else
149     self->string = rxpd_strdup (buf);
150
151   return self;
152 }
153
154 void
155 rxpd_rule_delete (struct rxpd_rule* rule)
156 {
157   if (rule)
158     {
159       llist_unlink (&rule->node);
160       if (rule->string[0] != '#')
161         regfree (&rule->rx);
162       free (rule->string);
163       free(rule);
164     }
165 }
166
167
168 //
169 struct rxpd_file*
170 rxpd_file_new (struct rxpd_base* base, const char* filename)
171 {
172   char buf[4096];
173   struct rxpd_file* self = NULL;
174
175   if (!filename ||
176       strcspn(filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
177       strlen (filename) + strlen (base->basedir) > 4095)
178     {
179       rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
180       return NULL;
181     }
182
183   strcpy (buf, base->basedir);
184   strcat (buf, filename);
185   filename = rxpd_strdup (buf);
186
187   self = rxpd_malloc (sizeof (struct rxpd_file));
188   self->filename = filename;
189   self->base = base;
190   const char* basename = strrchr (filename, '/');
191   if (basename)
192     ++basename;
193   else
194     basename = filename;
195   psplay_init (&self->node, basename);
196   llist_init (&self->rules);
197
198   psplay_insert (&base->files, &self->node);
199
200   rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
201   return self;
202 }
203
204 void
205 rxpd_file_delete (PSplay f)
206 {
207   if (f)
208     {
209       struct rxpd_file* file = (struct rxpd_file*)f;
210       LLIST_WHILE_HEAD (&file->rules, n)
211         {
212           struct rxpd_rule* node = (struct rxpd_rule*)n;
213           rxpd_rule_delete (node);
214         }
215       free ((void*)file->filename);
216       free (f);
217     }
218 }
219
220 int
221 rxpd_file_load (struct rxpd_file* self)
222 {
223   FILE* f = fopen (self->filename, "r");
224   // TODO error handling
225   if (f)
226     {
227       /* First purge old rules */
228       LLIST_WHILE_HEAD (&self->rules, n)
229         {
230           struct rxpd_rule* node = (struct rxpd_rule*)n;
231           rxpd_rule_delete (node);
232         }
233
234       // TODO test excess line length = error
235       char buf[4096];
236
237       rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->filename);
238
239       while (fgets (buf, 4096, f))
240         {
241           size_t last = strlen(buf);
242           if (buf[last-1] == '\n')
243             buf[last-1] = '\0';
244
245           struct rxpd_rule* rule;
246           rule = rxpd_rule_new (buf);
247           if (!rule)
248             abort();
249
250           rxpd_log (self->base, LOG_DEBUG, "new rule '%s'\n", rule->string);
251
252           llist_insert_tail (&self->rules, &rule->node);
253         }
254
255       fclose (f);
256       return 1;
257     }
258   else
259     {
260       rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->filename);
261       return 0;
262     }
263 }
264
265 int
266 rxpd_file_save (struct rxpd_file* self)
267 {
268   FILE* f = fopen (self->filename, "w");
269   // TODO error handling
270   if (f)
271     {
272       LLIST_FOREACH (&self->rules, n)
273         {
274           struct rxpd_rule* node = (struct rxpd_rule*)n;
275           fprintf (f, "%s\n", node->string);
276         }
277
278       fclose (f);
279       rxpd_log (self->base, LOG_NOTICE, "saved '%s'\n", self->filename);
280       return 1;
281     }
282   else
283     {
284       rxpd_log (self->base, LOG_ERR, "failed saving '%s'\n", self->filename);
285       return 0;
286     }
287 }
288
289 int
290 rxpd_file_cmp (const void* A, const void* B)
291 {
292   return strcmp (A, B);
293 }
294
295
296 //
297 struct rxpd_socket*
298 rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short port)
299 {
300   struct rxpd_socket* self;
301   self = rxpd_malloc (sizeof (struct rxpd_socket));
302
303   self->base = base;
304
305   llist_init (&self->node);
306
307   // TODO all abort() shall become rxpd_die
308   self->fd = socket (PF_INET, SOCK_STREAM, 0);
309   if (self->fd == -1)
310     abort ();
311
312   struct sockaddr_in listen_addr;
313   memset (&listen_addr, 0, sizeof (listen_addr));
314
315   listen_addr.sin_family = AF_INET;
316   if (addr)
317     {
318       if (inet_aton (addr, &listen_addr.sin_addr) == 0)
319         abort();
320     }
321   else
322     listen_addr.sin_addr.s_addr = INADDR_ANY;
323
324   listen_addr.sin_port = htons(port);
325
326   if (bind (self->fd, (struct sockaddr*)&listen_addr, sizeof (listen_addr)) == -1)
327     abort();
328
329   static int yes = 1;
330   if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
331     abort ();
332
333   if (listen (self->fd, 20) == -1)
334     abort ();
335
336   self->rxpd_socket_addr = rxpd_socket_tcp4addr;
337
338   event_set (&self->ev, self->fd, EV_READ, rxpd_socket_accept, self);
339   llist_insert_tail (&base->sockets, &self->node);
340
341   rxpd_log (base, LOG_INFO, "Listening on tcp4:%d\n", port);
342   return self;
343 }
344
345 int
346 rxpd_socket_tcp4addr (struct rxpd_connection* conn, char* dst, const char* pfx, size_t size)
347 {
348   struct sockaddr_in peer;
349   socklen_t len = sizeof (peer);
350   getpeername (conn->fd, (struct sockaddr*)&peer, &len);
351
352   char* addr;
353   addr = inet_ntoa (peer.sin_addr);
354   if (sizeof (":tcp4:") + strlen (pfx) + strlen (addr) > size)
355     return 0;
356
357   strcat (dst, pfx);
358   strcat (dst, ":tcp4:");
359   strcat (dst, addr);
360   return 1;
361 }
362
363
364
365 void
366 rxpd_socket_delete (struct rxpd_socket* self)
367 {
368   if (self)
369     {
370       event_del (&self->ev);
371       llist_unlink (&self->node);
372       close (self->fd);
373     }
374   free (self);
375 }
376
377 struct rxpd_socket*
378 rxpd_socket_schedule (struct rxpd_socket* self)
379 {
380   if (self)
381     {
382       event_add (&self->ev, NULL);
383     }
384   return self;
385 }
386
387 struct rxpd_socket*
388 rxpd_socket_suspend (struct rxpd_socket* self)
389 {
390   if (self)
391     {
392       event_del (&self->ev);
393     }
394   return self;
395 }
396
397 void
398 rxpd_socket_accept (int fd, short event, void* ptr)
399 {
400   (void) event;
401   struct rxpd_socket* self = ptr;
402
403   struct rxpd_connection* conn =
404     rxpd_connection_new (self, fd);
405
406   rxpd_connection_schedule (conn);
407   rxpd_socket_schedule (self);
408 }
409
410 ///
411
412 struct rxpd_buffer*
413 rxpd_buffer_init (struct rxpd_buffer* self, struct rxpd_connection* conn)
414 {
415   self->conn = conn;
416   self->state = RXPD_OK;
417   self->eol = self->eob = self->buffer;
418   self->buffer [4095] = '\0';
419   return self;
420 }
421
422
423 char*
424 rxpd_buffer_readline (struct rxpd_buffer* self, int again)
425 {
426   int fd = self->conn->fd;
427
428   if (self->eol < self->eob)
429     {
430       //there was a line pending, shift buffer left
431       memmove (self->buffer, self->eol+1, self->eob - self->eol - 1);
432       self->eob = (char*)(self->eob - (self->eol - self->buffer + 1));
433       self->eol = self->buffer;
434       // TODO handle \r's
435     }
436
437   if (!again && self->state == RXPD_OK)   // we only read when again is 0, first iteration
438     {
439       ssize_t r = 0;
440       do
441         {
442           r = read(fd, self->eob, 4095 - (self->eob - self->buffer));
443         }
444       while (r == -1 && errno == EINTR);
445
446       if (r != -1)
447         {
448
449           if (r == 0)
450             {
451               shutdown (fd, SHUT_RD);
452               self->state = RXPD_EOF;
453             }
454
455           self->eob += r;
456         }
457       else
458         self->state = RXPD_ERROR;
459     }
460
461   // find next newline, terminate string there
462   for (char* i = self->buffer; i < self->eob; ++i)
463     {
464       if (*i == '\n')
465         {
466           *i = '\0';
467           self->eol = i;
468           break;
469         }
470     }
471
472   // TODO handle buffer overfulls
473
474   return (self->eob == self->buffer) ? NULL : self->buffer;
475 }
476
477 /*
478 void
479 rxpd_buffer_write(int fd, short event, void* ptr)
480 {
481   struct rxpd_buffer* self = (struct rxpd_buffer*) ptr;
482
483   ssize_t n = write(int fd, const void *buf, size_t count);
484
485 }
486 */
487
488 int
489 rxpd_buffer_printf (struct rxpd_buffer* self, const char* fmt, ...)
490 {
491   // for now we do a blocking write, needs to be fixed some day
492   va_list ap;
493   va_start(ap, fmt);
494   int n = vsnprintf (self->buffer, 4096, fmt, ap);
495   va_end(ap);
496
497   write (self->conn->fd, self->buffer, n);
498
499   if (n>4095)
500     return 0;
501
502   return 1;
503 }
504
505
506
507
508 ///
509
510 struct rxpd_connection*
511 rxpd_connection_new (struct rxpd_socket* socket, int fd)
512 {
513   struct rxpd_connection* self;
514   self = rxpd_malloc (sizeof (struct rxpd_connection));
515
516   self->fd = accept (fd, NULL, 0);
517   if (self->fd == -1)
518     abort ();
519
520   self->socket = socket;
521   self->file = NULL;
522   self->tmp_str = NULL;
523   llist_init (&self->tmp_list);
524
525   rxpd_buffer_init (&self->in, self);
526   rxpd_buffer_init (&self->out, self);
527   
528   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_parse_cmd, self);
529
530   // TODO more info
531   rxpd_log (socket->base, LOG_INFO, "incoming connection\n");
532   return self;
533 }
534
535 void
536 rxpd_connection_delete (struct rxpd_connection* self)
537 {
538   if (self)
539     {
540       event_del (&self->ev);
541       close (self->fd);
542       free (self->tmp_str);
543       LLIST_WHILE_HEAD (&self->tmp_list, n)
544         {
545           struct rxpd_rule* node = (struct rxpd_rule*)n;
546           rxpd_rule_delete (node);
547         }
548     }
549   free (self);
550 }
551
552 struct rxpd_connection*
553 rxpd_connection_schedule (struct rxpd_connection* self)
554 {
555   if (self)
556     {
557       event_add (&self->ev, NULL);
558     }
559   return self;
560 }
561
562 int
563 rxpd_connection_check_policy (struct rxpd_connection* self, char* line)
564 {
565   struct rxpd_base* base = self->socket->base;
566   if (base->policy)
567     {
568       char buf[256];
569       buf[0] = '\0';
570
571       if (!self->socket->rxpd_socket_addr (self, buf, line, 256))
572         {
573           rxpd_log (base, LOG_ERR, "policy line too long\n");
574           return 0;
575         }
576
577       rxpd_log (base, LOG_DEBUG, "policy check '%s'\n", buf);
578
579       char* match = NULL;
580       LLIST_FOREACH (&base->policy->rules, n)
581       {
582         struct rxpd_rule* rule = (struct rxpd_rule*)n;
583         if (rule->string[0] != '#')
584           {
585             if (regexec (&rule->rx, buf, 0, NULL, 0) == 0)
586               {
587                 match = rule->string;
588                 break;
589               }
590           }
591       }
592
593       if (!match || strncmp("ACCEPT:", match, sizeof("ACCEPT:")-1) != 0)
594         {
595           rxpd_log (base, LOG_WARNING, "access denied '%s'\n", buf);
596           return 0;
597         }
598     }
599   return 1;
600 }
601 void
602 rxpd_connection_parse_cmd (int fd, short event, void* ptr)
603 {
604   (void) event;
605
606   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
607   struct rxpd_base* base = self->socket->base;
608
609   char* line;
610   line = rxpd_buffer_readline (&self->in, 0);
611
612   if (!line)
613     {
614       rxpd_log (base, LOG_ERR, "no data\n");
615       rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
616       close (fd);
617       return;
618     }
619
620   rxpd_log (base, LOG_DEBUG, "parse command '%s'\n", line);
621
622   static const struct cmd_table
623   {
624     enum rxpd_cmd_e nr;
625     const char* cmd;
626     size_t sz;
627   } cmds[] =
628     {
629 #define RXPD_CMD(cmd) {RXPD_CMD_##cmd, #cmd":", sizeof (#cmd)},
630       RXPD_COMMANDS
631 #undef RXPD_CMD
632       {0, NULL, 0}
633     };
634
635   const struct cmd_table* i;
636   for (i = cmds; i->cmd; ++i)
637     if (strncmp (line, i->cmd, i->sz) == 0)
638       break;
639   if (!i->cmd)
640     {
641       rxpd_log (base, LOG_ERR, "no command\n");
642       rxpd_buffer_printf (&self->out, "#ERROR: no command\n");
643       rxpd_connection_delete (self);
644       return;
645     }
646
647   if (!rxpd_connection_check_policy (self, line))
648     {
649       rxpd_buffer_printf (&self->out, "#ERROR: access denied\n");
650       rxpd_connection_delete (self);
651       return;
652     }
653
654   if (line[i->sz])
655     {
656       // rulename provided
657       self->file = (struct rxpd_file*) psplay_find (&base->files, &line[i->sz]);
658
659       if (!self->file)
660         {
661           self->file = rxpd_file_new (base, &line[i->sz]);
662           if (!self->file)
663             {
664               rxpd_log (base, LOG_ERR, "illeagal filename\n");
665               rxpd_buffer_printf (&self->out, "#ERROR: illegal filename\n");
666               rxpd_connection_delete (self);
667               return;
668             }
669         }
670     }
671
672   // dispatch
673   switch (i->nr)
674     {
675 #define RXPD_CMD(cmd)                                                           \
676 case RXPD_CMD_##cmd:                                                            \
677   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_cmd_##cmd, self);    \
678   rxpd_connection_cmd_##cmd (fd, 0, ptr);                                       \
679   break;
680       RXPD_COMMANDS
681 #undef RXPD_CMD
682     }
683 }
684
685
686
687 void
688 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
689 {
690   (void) fd;
691   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
692
693   if (event == EV_READ)
694     {
695       int again = -1;
696       char* line;
697       while ((line = rxpd_buffer_readline (&self->in, ++again)))
698         {
699           if (*line == '\0')
700             {
701               rxpd_buffer_printf (&self->out, "#OK:\n");
702             }
703           else
704             {
705               LLIST_FOREACH (&self->file->rules, n)
706                 {
707                   struct rxpd_rule* rule = (struct rxpd_rule*)n;
708                   if (rule->string[0] != '#')
709                     {
710                       if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
711                         {
712                           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
713                           break;
714                         }
715                     }
716                 }
717             }
718         }
719     }
720   else if (!self->file)
721     {
722       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
723       rxpd_connection_delete (self);
724       return;
725     }
726
727   if (rxpd_buffer_state (&self->in) == RXPD_OK)
728     rxpd_connection_schedule (self);
729   else
730     {
731       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
732         rxpd_buffer_printf (&self->out, "#ERROR:\n");
733       rxpd_connection_delete (self);
734     }
735 }
736
737
738
739 static void
740 rxpd_connection_APPEND_PREPEND_helper (short event, void* ptr, int do_append)
741 {
742   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
743
744   if (event == EV_READ)
745     {
746       int again = -1;
747       char* line;
748
749       while ((line = rxpd_buffer_readline (&self->in, ++again)))
750         {
751           if (*line)
752             {
753               struct rxpd_rule* rule;
754               rule = rxpd_rule_new (line);
755               if (!rule)
756                 abort();
757
758               llist_insert_tail (&self->tmp_list, &rule->node);
759             }
760           else goto finish;     /* move along, look elsewhere! This goto is not harmful and saves some code. */
761         }
762     }
763   else if (!event && !self->file)
764     {
765       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
766       rxpd_connection_delete (self);
767       return;
768     }
769
770   if (rxpd_buffer_state (&self->in) == RXPD_OK)
771     rxpd_connection_schedule (self);
772   else
773     {
774       // TODO should also print error when any rule compilation failed, use tmp_str to save case?
775       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
776         rxpd_buffer_printf (&self->out, "#ERROR:\n");
777       else
778         {
779         finish:
780           rxpd_buffer_printf (&self->out, "#OK:\n");
781         }
782
783       if (do_append)
784         llist_insertlist_prev (&self->file->rules, &self->tmp_list);
785       else
786         llist_insertlist_next (&self->file->rules, &self->tmp_list);
787       rxpd_connection_delete (self);
788     }
789 }
790
791 void
792 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
793 {
794   (void) fd;
795   rxpd_connection_APPEND_PREPEND_helper (event, ptr, 1);
796 }
797
798 void
799 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
800 {
801   (void) fd;
802   rxpd_connection_APPEND_PREPEND_helper (event, ptr, 0);
803 }
804
805
806 void
807 rxpd_connection_cmd_REMOVE (int fd, short event, void* ptr)
808 {
809   (void) fd;
810   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
811
812   if (event == EV_READ)
813     {
814       int again = -1;
815       char* line;
816       while ((line = rxpd_buffer_readline (&self->in, ++again)))
817         {
818           LLIST_FOREACH (&self->file->rules, n)
819             {
820               struct rxpd_rule* rule = (struct rxpd_rule*)n;
821               if (strcmp (rule->string, line) == 0)
822                 {
823                   LList tmp = llist_prev (n);
824                   rxpd_rule_delete (rule);
825                   n = tmp;
826                   rxpd_buffer_printf (&self->out, "#OK:\n");
827                   goto done;
828                 }
829             }
830           rxpd_buffer_printf (&self->out, "#ERROR: line not found\n");
831         done:
832           ;
833         }
834     }
835   else if (!self->file)
836     {
837       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
838       rxpd_connection_delete (self);
839       return;
840     }
841
842   if (rxpd_buffer_state (&self->in) == RXPD_OK)
843     rxpd_connection_schedule (self);
844   else
845     {
846       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
847         rxpd_buffer_printf (&self->out, "#ERROR:\n");
848       rxpd_connection_delete (self);
849     }
850 }
851
852
853 static int
854 rxpd_connection_do_REPLACE (struct rxpd_connection* self)
855 {
856   struct rxpd_rule* rule;
857
858   LLIST_FOREACH (&self->file->rules, n)
859     {
860       rule = (struct rxpd_rule*)n;
861       if (strcmp (rule->string, self->tmp_str) == 0)
862         goto found;
863     }
864   return 0;
865  found:
866   llist_insertlist_next (&rule->node, &self->tmp_list);
867   rxpd_rule_delete (rule);
868   free (self->tmp_str);
869   self->tmp_str = NULL;
870   return 1;
871 }
872
873 void
874 rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
875 {
876   (void) fd;
877   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
878
879   if (event == EV_READ)
880     {
881       int again = -1;
882       char* line;
883       while ((line = rxpd_buffer_readline (&self->in, ++again)))
884         {
885           if (self->tmp_str)
886             {
887               if (*line)
888                 {
889                   struct rxpd_rule* rule;
890                   rule = rxpd_rule_new (line);
891                   if (!rule)
892                     abort();
893
894                   llist_insert_tail (&self->tmp_list, &rule->node);
895                 }
896               /* TODO handle empty lines? */
897             }
898           else
899             self->tmp_str = rxpd_strdup (line);
900         }
901     }
902   else if (!self->file)
903     {
904       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
905       rxpd_connection_delete (self);
906       return;
907     }
908
909   if (rxpd_buffer_state (&self->in) == RXPD_OK)
910     rxpd_connection_schedule (self);
911   else
912     {
913       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
914         rxpd_buffer_printf (&self->out, "#ERROR:\n");
915       else
916         {
917           if (rxpd_connection_do_REPLACE (self))
918             rxpd_buffer_printf (&self->out, "#OK:\n");
919           else
920             rxpd_buffer_printf (&self->out, "#ERROR: rule matching '%s'\n", self->tmp_str);
921         }
922
923       rxpd_connection_delete (self);
924     }
925 }
926
927 void
928 rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
929 {
930   (void) fd;
931   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
932
933   if (!event)
934     {
935       if (self->file)
936         {
937           if (rxpd_file_load (self->file))
938             {
939               rxpd_buffer_printf (&self->out, "#OK:\n");
940             }
941           else
942             {
943               rxpd_buffer_printf (&self->out, "#ERROR: loading file '%s'\n", (const char*)self->file->node.key);
944             }
945         }
946       else
947         rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
948       rxpd_connection_delete (self);
949     }
950 }
951
952 void
953 rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
954 {
955   (void) fd;
956   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
957
958   if (!event)
959     {
960       if (self->file)
961         {
962           if (rxpd_file_save (self->file))
963             {
964               rxpd_buffer_printf (&self->out, "#OK:\n");
965             }
966           else
967             {
968               rxpd_buffer_printf (&self->out, "#ERROR: saving file '%s'\n", (const char*)self->file->node.key);
969             }
970         }
971       else
972         rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
973       rxpd_connection_delete (self);
974     }
975 }
976
977 void
978 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
979 {
980   (void) fd;
981   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
982
983   if (!event && !self->file)
984     {
985       rxpd_buffer_printf (&self->out, "#ERROR: no such file\n");
986       rxpd_connection_delete (self);
987       return;
988     }
989
990   if (llist_is_empty (&self->file->rules))
991     rxpd_buffer_printf (&self->out, "#OK:\n");
992   else
993     {
994       LLIST_FOREACH (&self->file->rules, n)
995         {
996           struct rxpd_rule* rule = (struct rxpd_rule*)n;
997           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
998         }
999     }
1000
1001   rxpd_connection_delete (self);
1002 }
1003
1004
1005 static psplay_delete_t
1006 walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
1007 {
1008   (void) level;
1009   struct rxpd_file* file = (struct rxpd_file*) node;
1010   struct rxpd_connection* conn = (struct rxpd_connection*) data;
1011
1012   if (which == PSPLAY_INORDER)
1013     rxpd_buffer_printf (&conn->out, "%s\n", file->node.key);
1014
1015   return PSPLAY_CONT;
1016 }
1017
1018
1019 void
1020 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
1021 {
1022   (void) fd;
1023   (void) event;
1024   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
1025   struct rxpd_base* base = self->socket->base;
1026
1027   if (psplay_isempty_root (&base->files))
1028     rxpd_buffer_printf (&self->out, "#OK:\n");
1029   else
1030     psplay_walk (&base->files, NULL, walk_LIST, 0, ptr);
1031
1032   rxpd_connection_delete (self);
1033 }
1034
1035 void
1036 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
1037 {
1038   (void) fd;
1039   (void) event;
1040   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
1041   struct rxpd_base* base = self->socket->base;
1042   // destroy all sockets
1043   LLIST_WHILE_HEAD (&base->sockets, n)
1044     {
1045       struct rxpd_socket* socket = (struct rxpd_socket*)n;
1046       rxpd_socket_delete (socket);
1047     }
1048   rxpd_buffer_printf (&self->out, "#OK:\n");
1049   rxpd_connection_delete (self);
1050 }