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