APPEND/PREPEND commands
[rxpd] / rxpd.c
diff --git a/rxpd.c b/rxpd.c
index bff71bc..2fe7b77 100644 (file)
--- a/rxpd.c
+++ b/rxpd.c
@@ -85,27 +85,32 @@ rxpd_rule_new (const char* buf)
       if (*buf != '#')
         {
           int err;
-          char* rxstart = strchr (buf, ':') + 1;
+          char* rxstart = strchr (buf, ':');
 
-          err = regcomp (&self->rx, rxstart, REG_EXTENDED|REG_ICASE|REG_NOSUB);
-
-          if (!err)
-            {
-              self->string = strdup (buf);
-              if (!self->string) abort();
-            }
+          if (!rxstart)
+            self->string = strdup ("#ERROR: Syntax error, line was neither a comment nor a rule");
           else
             {
-              regfree (&self->rx);
-              char ebuf[256];
-              size_t len = regerror (err, NULL, ebuf, 256);
-              self->string = malloc(len + strlen(buf) + 14);
-              if (!self->string) abort();
-              strcpy (self->string, "#ERROR ");
-              strcat (self->string, ebuf);
-              strcat (self->string, " in '");
-              strcat (self->string, buf);
-              strcat (self->string, "'");
+              err = regcomp (&self->rx, rxstart+1, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+
+              if (!err)
+                {
+                  self->string = strdup (buf);
+                  if (!self->string) abort();
+                }
+              else
+                {
+                  regfree (&self->rx);
+                  char ebuf[256];
+                  size_t len = regerror (err, NULL, ebuf, 256);
+                  self->string = malloc(len + strlen(buf) + 14);
+                  if (!self->string) abort();
+                  strcpy (self->string, "#ERROR: ");
+                  strcat (self->string, ebuf);
+                  strcat (self->string, " in '");
+                  strcat (self->string, buf);
+                  strcat (self->string, "'");
+                }
             }
         }
       else
@@ -205,7 +210,7 @@ rxpd_file_load (struct rxpd_file* self)
           if (!rule)
             abort();
 
-          printf("%s\n", rule->string);
+          printf("loaded rule '%s'\n", rule->string);
 
           llist_insert_tail (&self->rules, &rule->node);
         }
@@ -532,8 +537,10 @@ rxpd_connection_parse_cmd (int fd, short event, void* ptr)
     {
       // rulename provided
       self->file = (struct rxpd_file*) psplay_find (&self->base->files, &line[i->sz]);
+
       if (!self->file)
         {
+          // todo create policy?
           self->file = rxpd_file_new (self->base, &line[i->sz]);
           if (!self->file)
             {
@@ -550,38 +557,119 @@ rxpd_connection_parse_cmd (int fd, short event, void* ptr)
 #define RXPD_CMD(cmd)                                                           \
 case RXPD_CMD_##cmd:                                                            \
   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_cmd_##cmd, self);    \
+  rxpd_connection_cmd_##cmd (fd, 0, ptr);                                       \
   break;
       RXPD_COMMANDS
 #undef RXPD_CMD
     }
-  rxpd_connection_schedule (self);
 }
 
+
+
 void
 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
 {
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  LLIST_FOREACH (&self->file.rules, node)
-  
 
-    //rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
+  if (event == EV_READ)
+    {
+      int again = -1;
+      char* line;
+      while (line = rxpd_buffer_readline (&self->in, ++again))
+        {
+          if (*line == '\0')
+            {
+              rxpd_buffer_printf (&self->out, "#OK:\n");
+            }
+          else
+            {
+              LLIST_FOREACH (&self->file->rules, n)
+                {
+                  struct rxpd_rule* rule = (struct rxpd_rule*)n;
+                  if (rule->string[0] != '#')
+                    {
+                      if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
+                        {
+                          rxpd_buffer_printf (&self->out, "%s\n", rule->string);
+                          break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+  if (rxpd_buffer_state (&self->in) == RXPD_OK)
+    rxpd_connection_schedule (self);
+  else
+    {
+      if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
+        rxpd_buffer_printf (&self->out, "#ERROR:\n");
+      close (fd);
+    }
+}
+
+
 
+static void
+rxpd_connection_APPEND_PREPEND_helper (int fd, short event, void* ptr, int do_append)
+{
+  struct rxpd_connection* self = (struct rxpd_connection*) ptr;
+
+  if (!event)
+    llist_init (&self->tmp_list);
+
+  if (event == EV_READ)
+    {
+      int again = -1;
+      char* line;
 
-  rxpd_connection_schedule (self);
+      while (line = rxpd_buffer_readline (&self->in, ++again))
+        {
+          if (*line)
+            {
+              struct rxpd_rule* rule;
+              rule = rxpd_rule_new (line);
+              if (!rule)
+                abort();
+
+              llist_insert_tail (&self->tmp_list, &rule->node);
+            }
+          else goto finish;
+        }
+    }
+
+  if (rxpd_buffer_state (&self->in) == RXPD_OK)
+    rxpd_connection_schedule (self);
+  else
+    {
+      // TODO should also print error when any rule compilation failed
+      if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
+        rxpd_buffer_printf (&self->out, "#ERROR:\n");
+      else
+        {
+        finish:
+          rxpd_buffer_printf (&self->out, "#OK:\n");
+        }
+
+      if (do_append)
+        llist_insertlist_prev (&self->file->rules, &self->tmp_list);
+      else
+        llist_insertlist_next (&self->file->rules, &self->tmp_list);
+      close (fd);
+    }
 }
 
 void
 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
 {
-  struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
+  rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 1);
 }
 
 void
 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
 {
-  struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
+  rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 0);
 }
 
 void
@@ -616,20 +704,65 @@ void
 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
 {
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
+
+  if (llist_is_empty (&self->file->rules))
+    rxpd_buffer_printf (&self->out, "#OK:\n");
+  else
+    {
+      LLIST_FOREACH (&self->file->rules, n)
+        {
+          struct rxpd_rule* rule = (struct rxpd_rule*)n;
+          rxpd_buffer_printf (&self->out, "%s\n", rule->string);
+        }
+    }
+
+  close (fd);
 }
 
+
+static psplay_delete_t
+walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
+{
+  (void) level;
+  struct rxpd_file* file = (struct rxpd_file*) node;
+  struct rxpd_connection* conn = (struct rxpd_connection*) data;
+
+  if (which == PSPLAY_INORDER)
+    rxpd_buffer_printf (&conn->out, "%s\n", file->node.key);
+
+  return PSPLAY_CONT;
+}
+
+
 void
 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
 {
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
+
+  if (psplay_isempty_root (&self->base->files))
+    rxpd_buffer_printf (&self->out, "#OK:\n");
+  else
+    psplay_walk (&self->base->files, NULL, walk_LIST, 0, ptr);
+
+  close (fd);
 }
 
 void
 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
 {
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
-  rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
-}
+  // destroy all sockets
+  LLIST_WHILE_HEAD (&self->base->sockets_pending, n)
+    {
+      struct rxpd_socket* socket = (struct rxpd_socket*)n;
+      rxpd_socket_delete (socket);
+    }
+  LLIST_WHILE_HEAD (&self->base->sockets_active, n)
+    {
+      struct rxpd_socket* socket = (struct rxpd_socket*)n;
+      rxpd_socket_delete (socket);
+    }
 
+  rxpd_buffer_printf (&self->out, "#OK:\n");
+  close (fd);
+}