chiark / gitweb /
split out disorder-server.deb
[disorder] / server / server.c
index cb7714e16b2ac82ef5d496fd7d508bb7f1133d8a..5a11b8cd05c8c6ac278e248621df339f3d0d47f6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2006 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,6 +42,7 @@
 #include "server.h"
 #include "syscalls.h"
 #include "queue.h"
+#include "server-queue.h"
 #include "play.h"
 #include "log.h"
 #include "mem.h"
@@ -139,6 +140,8 @@ static int reader_error(ev_source attribute((unused)) *ev,
   D(("server reader_error %d %d", fd, errno_value));
   error(errno, "S%x read error on socket", c->tag);
   ev_writer_cancel(c->w);
+  ev_report(ev);
+  info("closing fd %d", fd);
   xclose(fd);
   return 0;
 }
@@ -391,7 +394,8 @@ static int c_user(struct conn *c,
     sink_writes(ev_writer_sink(c->w), "530 authentication failed\n");
     return 1;
   }
-  res = authhash(c->nonce, sizeof c->nonce, config->allow.s[n].s[1]);
+  res = authhash(c->nonce, sizeof c->nonce, config->allow.s[n].s[1],
+                config->authorization_algorithm);
   if(wideopen || (res && !strcmp(res, vec[1]))) {
     c->who = vec[0];
     /* currently we only bother logging remote connections */
@@ -759,6 +763,12 @@ static int c_log(struct conn *c,
   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
              (uintmax_t)now, 
              paused ? "pause" : "resume");
+  if(playing)
+    sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state playing\n",
+               (uintmax_t)now);
+  /* Initial volume */
+  sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" volume %d %d\n",
+             (uintmax_t)now, volume_left, volume_right);
   c->lo = xmalloc(sizeof *c->lo);
   c->lo->fn = logclient;
   c->lo->user = c;
@@ -770,8 +780,8 @@ static int c_log(struct conn *c,
 static void post_move_cleanup(void) {
   struct queue_entry *q;
 
-  /* If we have caused the random track to not be at the end then we make it no
-   * longer be random. */
+  /* If we have caused any random tracks to not be at the end then we make them
+   * no longer be random. */
   for(q = qhead.next; q != &qhead; q = q->next)
     if(q->state == playing_random && q->next != &qhead)
       q->state = playing_unplayed;
@@ -907,6 +917,34 @@ static int c_nop(struct conn *c,
   return 1;
 }
 
+static int c_new(struct conn *c,
+                char **vec,
+                int nvec) {
+  char **tracks = trackdb_new(0, nvec > 0 ? atoi(vec[0]) : INT_MAX);
+
+  sink_printf(ev_writer_sink(c->w), "253 New track list follows\n");
+  while(*tracks) {
+    sink_printf(ev_writer_sink(c->w), "%s%s\n",
+               **tracks == '.' ? "." : "", *tracks);
+    ++tracks;
+  }
+  sink_writes(ev_writer_sink(c->w), ".\n");
+  return 1;                            /* completed */
+
+}
+
+static int c_rtp_address(struct conn *c,
+                        char attribute((unused)) **vec,
+                        int attribute((unused)) nvec) {
+  if(config->speaker_backend == BACKEND_NETWORK) {
+    sink_printf(ev_writer_sink(c->w), "252 %s %s\n",
+               quoteutf8(config->broadcast.s[0]),
+               quoteutf8(config->broadcast.s[1]));
+  } else
+    sink_writes(ev_writer_sink(c->w), "550 No RTP\n");
+  return 1;
+}
 #define C_AUTH         0001            /* must be authenticated */
 #define C_TRUSTED      0002            /* must be trusted user */
 
@@ -930,6 +968,7 @@ static const struct command {
   { "log",            0, 0,       c_log,            C_AUTH },
   { "move",           2, 2,       c_move,           C_AUTH },
   { "moveafter",      1, INT_MAX, c_moveafter,      C_AUTH },
+  { "new",            0, 1,       c_new,            C_AUTH },
   { "nop",            0, 0,       c_nop,            C_AUTH },
   { "part",           3, 3,       c_part,           C_AUTH },
   { "pause",          0, 0,       c_pause,          C_AUTH },
@@ -946,6 +985,7 @@ static const struct command {
   { "rescan",         0, 0,       c_rescan,         C_AUTH|C_TRUSTED },
   { "resolve",        1, 1,       c_resolve,        C_AUTH },
   { "resume",         0, 0,       c_resume,         C_AUTH },
+  { "rtp-address",    0, 0,       c_rtp_address,    C_AUTH },
   { "scratch",        0, 1,       c_scratch,        C_AUTH },
   { "search",         1, 1,       c_search,         C_AUTH },
   { "set",            3, 3,       c_set,            C_AUTH, },
@@ -1072,13 +1112,23 @@ static int listen_callback(ev_source *ev,
   cloexec(fd);
   c->tag = tags++;
   c->ev = ev;
-  c->w = ev_writer_new(ev, fd, writer_error, c);
-  c->r = ev_reader_new(ev, fd, redirect_reader_callback, reader_error, c);
+  c->w = ev_writer_new(ev, fd, writer_error, c,
+                      "client writer");
+  c->r = ev_reader_new(ev, fd, redirect_reader_callback, reader_error, c,
+                      "client reader");
   c->fd = fd;
   c->reader = reader_callback;
   c->l = l;
   gcry_randomize(c->nonce, sizeof c->nonce, GCRY_STRONG_RANDOM);
-  sink_printf(ev_writer_sink(c->w), "231 %s\n", hex(c->nonce, sizeof c->nonce));
+  if(!strcmp(config->authorization_algorithm, "sha1")
+     || !strcmp(config->authorization_algorithm, "SHA1")) {
+    sink_printf(ev_writer_sink(c->w), "231 %s\n",
+               hex(c->nonce, sizeof c->nonce));
+  } else {
+    sink_printf(ev_writer_sink(c->w), "231 %s %s\n",
+               config->authorization_algorithm,
+               hex(c->nonce, sizeof c->nonce));
+  }
   return 0;
 }
 
@@ -1101,7 +1151,8 @@ int server_start(ev_source *ev, int pf,
   cloexec(fd);
   l->name = name;
   l->pf = pf;
-  if(ev_listen(ev, fd, listen_callback, l)) exit(EXIT_FAILURE);
+  if(ev_listen(ev, fd, listen_callback, l, "server listener"))
+    exit(EXIT_FAILURE);
   return fd;
 }