X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f08c0859513712f805da09ae1e1bcefb436b4096..5dba54ab01bce6ca8a6f1fd64b46cd304501b596:/server/server-queue.c
diff --git a/server/server-queue.c b/server/server-queue.c
index 2b0e89e..763f4f3 100644
--- a/server/server-queue.c
+++ b/server/server-queue.c
@@ -1,67 +1,39 @@
/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
+ * Copyright (C) 2004-2009 Richard Kettlewell
*
- * This program is free software; you can redistribute it and/or modify
+ * 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
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * along with this program. If not, see .
*/
-
-#include
-#include "types.h"
-
-#include
-#include
-#include
-#include
-#include
-
-#include "mem.h"
-#include "log.h"
-#include "split.h"
-#include "printf.h"
-#include "queue.h"
-#include "server-queue.h"
-#include "eventlog.h"
-#include "plugin.h"
-#include "basen.h"
-#include "configuration.h"
-#include "inputline.h"
-#include "disorder.h"
+/** @file server/server-queue.c
+ * @brief Server-specific track queue support
+ */
+#include "disorder-server.h"
/* the head of the queue is played next, so normally we add to the tail */
-struct queue_entry qhead = { &qhead, &qhead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+struct queue_entry qhead = {
+ .next = &qhead,
+ .prev = &qhead
+};
/* the head of the recent list is the oldest thing, the tail the most recently
* played */
-struct queue_entry phead = { &phead, &phead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+struct queue_entry phead = {
+ .next = &phead,
+ .prev = &phead
+};
-static long pcount;
-
-/* add new entry @n@ to a doubly linked list just after @b@ */
-static void l_add(struct queue_entry *b, struct queue_entry *n) {
- n->prev = b;
- n->next = b->next;
- n->next->prev = n;
- n->prev->next = n;
-}
-
-/* remove an entry from a doubly-linked list */
-static void l_remove(struct queue_entry *node) {
- node->next->prev = node->prev;
- node->prev->next = node->next;
-}
+long pcount;
void queue_fix_sofar(struct queue_entry *q) {
long sofar;
@@ -78,41 +50,66 @@ void queue_fix_sofar(struct queue_entry *q) {
if(q->uptopause == -1) /* Don't know how far thru. */
sofar = -1;
else if(q->lastresumed) /* Has been paused and resumed. */
- sofar = q->uptopause + time(0) - q->lastresumed;
+ sofar = q->uptopause + xtime(0) - q->lastresumed;
else /* Currently paused. */
sofar = q->uptopause;
} else /* Never been paused. */
- sofar = time(0) - q->played;
+ sofar = xtime(0) - q->played;
q->sofar = sofar;
}
}
static void queue_read_error(const char *msg,
void *u) {
- fatal(0, "error parsing queue %s: %s", (const char *)u, msg);
+ disorder_fatal(0, "error parsing queue %s: %s", (const char *)u, msg);
}
static void queue_do_read(struct queue_entry *head, const char *path) {
char *buffer;
FILE *fp;
struct queue_entry *q;
+ int ver = 0;
if(!(fp = fopen(path, "r"))) {
if(errno == ENOENT)
return; /* no queue */
- fatal(errno, "error opening %s", path);
+ disorder_fatal(errno, "error opening %s", path);
}
head->next = head->prev = head;
while(!inputline(path, fp, &buffer, '\n')) {
+ if(buffer[0] == '#') {
+ /* Version indicator */
+ ver = atoi(buffer + 1);
+ continue;
+ }
q = xmalloc(sizeof *q);
queue_unmarshall(q, buffer, queue_read_error, (void *)path);
+ if(ver < 1) {
+ /* Fix up origin field as best we can; will be wrong in some cases but
+ * hopefully not too horribly so. */
+ q->origin = q->submitter ? origin_picked : origin_random;
+ /* Eliminated obsolete states, since they are assumed elsewhere not to be
+ * set. */
+ switch(q->state) {
+ case playing_isscratch:
+ q->origin = origin_scratch;
+ q->state = playing_unplayed;
+ break;
+ case playing_random:
+ q->state = playing_unplayed;
+ break;
+ default:
+ break;
+ }
+ }
if(head == &qhead
&& (!q->track
|| !q->when))
- fatal(0, "incomplete queue entry in %s", path);
- l_add(head->prev, q);
+ disorder_fatal(0, "incomplete queue entry in %s", path);
+ queue_insert_entry(head->prev, q);
}
- if(ferror(fp)) fatal(errno, "error reading %s", path);
+ if(ferror(fp))
+ disorder_fatal(errno, "error reading %s", path);
fclose(fp);
}
@@ -139,12 +136,15 @@ static void queue_do_write(const struct queue_entry *head, const char *path) {
struct queue_entry *q;
byte_xasprintf(&tmp, "%s.new", path);
- if(!(fp = fopen(tmp, "w"))) fatal(errno, "error opening %s", tmp);
+ if(!(fp = fopen(tmp, "w"))) disorder_fatal(errno, "error opening %s", tmp);
+ /* Save version indicator */
+ if(fprintf(fp, "#1\n") < 0)
+ disorder_fatal(errno, "error writing %s", tmp);
for(q = head->next; q != head; q = q->next)
if(fprintf(fp, "%s\n", queue_marshall(q)) < 0)
- fatal(errno, "error writing %s", tmp);
- if(fclose(fp) < 0) fatal(errno, "error closing %s", tmp);
- if(rename(tmp, path) < 0) fatal(errno, "error replacing %s", path);
+ disorder_fatal(errno, "error writing %s", tmp);
+ if(fclose(fp) < 0) disorder_fatal(errno, "error closing %s", tmp);
+ if(rename(tmp, path) < 0) disorder_fatal(errno, "error replacing %s", path);
}
void queue_write(void) {
@@ -155,148 +155,6 @@ void recent_write(void) {
queue_do_write(&phead, config_get_file("recent"));
}
-static void queue_id(struct queue_entry *q) {
- static unsigned long serial;
- unsigned long a[3];
- char buffer[128];
-
- a[0] = serial++ & 0xFFFFFFFFUL;
- a[1] = time(0) & 0xFFFFFFFFUL;
- a[2] = getpid() & 0xFFFFFFFFUL;
- basen(a, 3, buffer, sizeof buffer, 62);
- q->id = xstrdup(buffer);
-}
-
-struct queue_entry *queue_add(const char *track, const char *submitter,
- int where) {
- struct queue_entry *q, *beforeme;
-
- q = xmalloc(sizeof *q);
- q->track = xstrdup(track);
- q->submitter = submitter ? xstrdup(submitter) : 0;
- q->state = playing_unplayed;
- queue_id(q);
- time(&q->when);
- switch(where) {
- case WHERE_START:
- l_add(&qhead, q);
- break;
- case WHERE_END:
- l_add(qhead.prev, q);
- break;
- case WHERE_BEFORE_RANDOM:
- /* We want to find the point in the queue before the block of random tracks
- * at the end. */
- beforeme = &qhead;
- while(beforeme->prev != &qhead
- && beforeme->prev->state == playing_random)
- beforeme = beforeme->prev;
- l_add(beforeme->prev, q);
- break;
- }
- /* submitter will be a null pointer for a scratch */
- if(submitter)
- notify_queue(track, submitter);
- eventlog_raw("queue", queue_marshall(q), (const char *)0);
- return q;
-}
-
-int queue_move(struct queue_entry *q, int delta, const char *who) {
- int moved = 0;
- char buffer[20];
-
- /* not the most efficient approach but hopefuly relatively comprehensible:
- * the idea is that for each step we determine which nodes are affected, and
- * fill in all the links starting at the 'prev' end and moving towards the
- * 'next' end. */
-
- while(delta > 0 && q->prev != &qhead) {
- struct queue_entry *n, *p, *pp;
-
- n = q->next;
- p = q->prev;
- pp = p->prev;
- pp->next = q;
- q->prev = pp;
- q->next = p;
- p->prev = q;
- p->next = n;
- n->prev = p;
- --delta;
- ++moved;
- }
-
- while(delta < 0 && q->next != &qhead) {
- struct queue_entry *n, *p, *nn;
-
- p = q->prev;
- n = q->next;
- nn = n->next;
- p->next = n;
- n->prev = p;
- n->next = q;
- q->prev = n;
- q->next = nn;
- nn->prev = q;
- ++delta;
- --moved;
- }
-
- if(moved) {
- info("user %s moved %s", who, q->id);
- notify_queue_move(q->track, who);
- sprintf(buffer, "%d", moved);
- eventlog("moved", who, (char *)0);
- }
-
- return delta;
-}
-
-static int find_in_list(struct queue_entry *needle,
- int nqs, struct queue_entry **qs) {
- int n;
-
- for(n = 0; n < nqs; ++n)
- if(qs[n] == needle)
- return 1;
- return 0;
-}
-
-void queue_moveafter(struct queue_entry *target,
- int nqs, struct queue_entry **qs,
- const char *who) {
- struct queue_entry *q;
- int n;
-
- /* Normalize */
- if(!target)
- target = &qhead;
- else
- while(find_in_list(target, nqs, qs))
- target = target->prev;
- /* Do the move */
- for(n = 0; n < nqs; ++n) {
- q = qs[n];
- l_remove(q);
- l_add(target, q);
- target = q;
- /* Log the individual tracks */
- info("user %s moved %s", who, q->id);
- notify_queue_move(q->track, who);
- }
- /* Report that the queue changed to the event log */
- eventlog("moved", who, (char *)0);
-}
-
-void queue_remove(struct queue_entry *which, const char *who) {
- if(who) {
- info("user %s removed %s", who, which->id);
- notify_queue_move(which->track, who);
- }
- eventlog("removed", which->id, who, (const char *)0);
- l_remove(which);
-}
-
struct queue_entry *queue_find(const char *key) {
struct queue_entry *q;
@@ -307,19 +165,6 @@ struct queue_entry *queue_find(const char *key) {
return q != &qhead ? q : 0;
}
-void queue_played(struct queue_entry *q) {
- while(pcount && pcount >= config->history) {
- eventlog("recent_removed", phead.next->id, (char *)0);
- l_remove(phead.next);
- pcount--;
- }
- if(config->history) {
- eventlog_raw("recent_added", queue_marshall(q), (char *)0);
- l_add(phead.prev, q);
- ++pcount;
- }
-}
-
/*
Local Variables:
c-basic-offset:2