chiark / gitweb /
New 'new_max' configuration bounds the number of tracks that 'new'
[disorder] / server / server.c
index 1e7c22fcc88d0166d71507c299833152130d61f0..69129c9be600b86873f81957a6eb065186cc2b56 100644 (file)
@@ -118,8 +118,13 @@ struct conn {
   char *cookie;
   /** @brief Connection rights */
   rights_type rights;
+  /** @brief Next connection */
+  struct conn *next;
 };
 
+/** @brief Linked list of connections */
+static struct conn *connections;
+
 static int reader_callback(ev_source *ev,
                           ev_reader *reader,
                           void *ptr,
@@ -129,6 +134,16 @@ static int reader_callback(ev_source *ev,
 
 static const char *noyes[] = { "no", "yes" };
 
+/** @brief Remove a connection from the connection list */
+static void remove_connection(struct conn *c) {
+  struct conn **cc;
+
+  for(cc = &connections; *cc && *cc != c; cc = &(*cc)->next)
+    ;
+  if(*cc)
+    *cc = c->next;
+}
+
 /** @brief Called when a connection's writer fails or is shut down
  *
  * If the connection still has a raeder that is cancelled.
@@ -154,6 +169,7 @@ static int writer_error(ev_source attribute((unused)) *ev,
   }
   c->w = 0;
   ev_report(ev);
+  remove_connection(c);
   return 0;
 }
 
@@ -173,6 +189,7 @@ static int reader_error(ev_source attribute((unused)) *ev,
   c->w = 0;
   c->r = 0;
   ev_report(ev);
+  remove_connection(c);
   return 0;
 }
 
@@ -339,7 +356,7 @@ static int c_rescan(struct conn *c,
                    char attribute((unused)) **vec,
                    int attribute((unused)) nvec) {
   info("S%x rescan by %s", c->tag, c->who);
-  trackdb_rescan(c->ev);
+  trackdb_rescan(c->ev, 1/*check*/);
   sink_writes(ev_writer_sink(c->w), "250 initiated rescan\n");
   return 1;                            /* completed */
 }
@@ -785,6 +802,7 @@ static int logging_reader_callback(ev_source attribute((unused)) *ev,
       c->w = 0;
     }
     c->r = 0;
+    remove_connection(c);
   }
   return 0;
 }
@@ -977,9 +995,18 @@ static int c_nop(struct conn *c,
 static int c_new(struct conn *c,
                 char **vec,
                 int nvec) {
-  char **tracks = trackdb_new(0, nvec > 0 ? atoi(vec[0]) : INT_MAX);
+  int max, n;
+  char **tracks;
 
+  if(nvec > 0)
+    max = atoi(vec[0]);
+  else
+    max = INT_MAX;
+  if(max <= 0 || max > config->new_max)
+    max = config->new_max;
+  tracks = trackdb_new(0, max);
   sink_printf(ev_writer_sink(c->w), "253 New track list follows\n");
+  n = 0;
   while(*tracks) {
     sink_printf(ev_writer_sink(c->w), "%s%s\n",
                **tracks == '.' ? "." : "", *tracks);
@@ -1085,26 +1112,50 @@ static int c_adduser(struct conn *c,
 static int c_deluser(struct conn *c,
                     char **vec,
                     int attribute((unused)) nvec) {
-  if(trackdb_deluser(vec[0]))
+  struct conn *d;
+
+  if(trackdb_deluser(vec[0])) {
     sink_writes(ev_writer_sink(c->w), "550 Cannot delete user\n");
-  else
-    sink_writes(ev_writer_sink(c->w), "250 User deleted\n");
+    return 1;
+  }
+  /* Zap connections belonging to deleted user */
+  for(d = connections; d; d = d->next)
+    if(!strcmp(d->who, vec[0]))
+      d->rights = 0;
+  sink_writes(ev_writer_sink(c->w), "250 User deleted\n");
   return 1;
 }
 
 static int c_edituser(struct conn *c,
                      char **vec,
                      int attribute((unused)) nvec) {
+  struct conn *d;
+
   /* RIGHT_ADMIN can do anything; otherwise you can only set your own email
    * address and password. */
   if((c->rights & RIGHT_ADMIN)
      || (!strcmp(c->who, vec[0])
         && (!strcmp(vec[1], "email")
             || !strcmp(vec[1], "password")))) {
-    if(trackdb_edituserinfo(vec[0], vec[1], vec[2]))
+    if(trackdb_edituserinfo(vec[0], vec[1], vec[2])) {
       sink_writes(ev_writer_sink(c->w), "550 Failed to change setting\n");
-    else
-      sink_writes(ev_writer_sink(c->w), "250 OK\n");
+      return 1;
+    }
+    if(!strcmp(vec[1], "password")) {
+      /* Zap all connections for this user after a password change */
+      for(d = connections; d; d = d->next)
+       if(!strcmp(d->who, vec[0]))
+         d->rights = 0;
+    } else if(!strcmp(vec[1], "rights")) {
+      /* Update rights for this user */
+      rights_type r;
+
+      if(parse_rights(vec[1], &r, 1))
+       for(d = connections; d; d = d->next)
+         if(!strcmp(d->who, vec[0]))
+           d->rights = r;
+    }
+    sink_writes(ev_writer_sink(c->w), "250 OK\n");
   } else {
     error(0, "%s attempted edituser but lacks required rights", c->who);
     sink_writes(ev_writer_sink(c->w), "510 Restricted to administrators\n");
@@ -1396,6 +1447,7 @@ static int reader_callback(ev_source attribute((unused)) *ev,
       ev_writer_close(c->w);
       c->w = 0;
     }
+    remove_connection(c);
   }
   return 0;
 }