chiark / gitweb /
Doxygen file headers for most files
[disorder] / server / queue-ops.c
CommitLineData
05b75f8d
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2008 Richard Kettlewell
4 *
e7eb3a27 5 * This program is free software: you can redistribute it and/or modify
05b75f8d 6 * it under the terms of the GNU General Public License as published by
e7eb3a27 7 * the Free Software Foundation, either version 3 of the License, or
05b75f8d
RK
8 * (at your option) any later version.
9 *
e7eb3a27
RK
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
05b75f8d 15 * You should have received a copy of the GNU General Public License
e7eb3a27 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
05b75f8d 17 */
132a5a4a
RK
18/** @file server/queue-ops.c
19 * @brief Track queues (server-specific code)
20 */
05b75f8d
RK
21#include "disorder-server.h"
22
23static int find_in_list(struct queue_entry *needle,
24 int nqs, struct queue_entry **qs) {
25 int n;
26
27 for(n = 0; n < nqs; ++n)
28 if(qs[n] == needle)
29 return 1;
30 return 0;
31}
32
33static int id_in_use(const char *id) {
34 struct queue_entry *q;
35
36 for(q = qhead.next; q != &qhead; q = q->next)
37 if(!strcmp(id, q->id))
38 return 1;
39 return 0;
40}
41
42static void queue_id(struct queue_entry *q) {
43 const char *id;
44
45 id = random_id();
46 while(id_in_use(id))
47 id = random_id();
48 q->id = id;
49}
50
51struct queue_entry *queue_add(const char *track, const char *submitter,
52 int where) {
53 struct queue_entry *q, *beforeme;
54
55 q = xmalloc(sizeof *q);
56 q->track = xstrdup(track);
57 q->submitter = submitter ? xstrdup(submitter) : 0;
58 q->state = playing_unplayed;
59 queue_id(q);
60 time(&q->when);
61 switch(where) {
62 case WHERE_START:
63 queue_insert_entry(&qhead, q);
64 break;
65 case WHERE_END:
66 queue_insert_entry(qhead.prev, q);
67 break;
68 case WHERE_BEFORE_RANDOM:
69 /* We want to find the point in the queue before the block of random tracks
70 * at the end. */
71 beforeme = &qhead;
72 while(beforeme->prev != &qhead
73 && beforeme->prev->state == playing_random)
74 beforeme = beforeme->prev;
75 queue_insert_entry(beforeme->prev, q);
76 break;
77 }
78 /* submitter will be a null pointer for a scratch */
79 if(submitter)
80 notify_queue(track, submitter);
81 eventlog_raw("queue", queue_marshall(q), (const char *)0);
82 return q;
83}
84
85int queue_move(struct queue_entry *q, int delta, const char *who) {
86 int moved = 0;
87 char buffer[20];
88
89 /* not the most efficient approach but hopefuly relatively comprehensible:
90 * the idea is that for each step we determine which nodes are affected, and
91 * fill in all the links starting at the 'prev' end and moving towards the
92 * 'next' end. */
93
94 while(delta > 0 && q->prev != &qhead) {
95 struct queue_entry *n, *p, *pp;
96
97 n = q->next;
98 p = q->prev;
99 pp = p->prev;
100 pp->next = q;
101 q->prev = pp;
102 q->next = p;
103 p->prev = q;
104 p->next = n;
105 n->prev = p;
106 --delta;
107 ++moved;
108 }
109
110 while(delta < 0 && q->next != &qhead) {
111 struct queue_entry *n, *p, *nn;
112
113 p = q->prev;
114 n = q->next;
115 nn = n->next;
116 p->next = n;
117 n->prev = p;
118 n->next = q;
119 q->prev = n;
120 q->next = nn;
121 nn->prev = q;
122 ++delta;
123 --moved;
124 }
125
126 if(moved) {
127 info("user %s moved %s", who, q->id);
128 notify_queue_move(q->track, who);
129 sprintf(buffer, "%d", moved);
130 eventlog("moved", who, (char *)0);
131 }
132
133 return delta;
134}
135
136void queue_moveafter(struct queue_entry *target,
137 int nqs, struct queue_entry **qs,
138 const char *who) {
139 struct queue_entry *q;
140 int n;
141
142 /* Normalize */
143 if(!target)
144 target = &qhead;
145 else
146 while(find_in_list(target, nqs, qs))
147 target = target->prev;
148 /* Do the move */
149 for(n = 0; n < nqs; ++n) {
150 q = qs[n];
151 queue_delete_entry(q);
152 queue_insert_entry(target, q);
153 target = q;
154 /* Log the individual tracks */
155 info("user %s moved %s", who, q->id);
156 notify_queue_move(q->track, who);
157 }
158 /* Report that the queue changed to the event log */
159 eventlog("moved", who, (char *)0);
160}
161
162void queue_remove(struct queue_entry *which, const char *who) {
163 if(who) {
164 info("user %s removed %s", who, which->id);
165 notify_queue_move(which->track, who);
166 }
167 eventlog("removed", which->id, who, (const char *)0);
168 queue_delete_entry(which);
169}
170
171void queue_played(struct queue_entry *q) {
172 while(pcount && pcount >= config->history) {
173 eventlog("recent_removed", phead.next->id, (char *)0);
174 queue_delete_entry(phead.next);
175 pcount--;
176 }
177 if(config->history) {
178 eventlog_raw("recent_added", queue_marshall(q), (char *)0);
179 queue_insert_entry(phead.prev, q);
180 ++pcount;
181 }
182}
183
184/*
185Local Variables:
186c-basic-offset:2
187comment-column:40
188fill-column:79
189indent-tabs-mode:nil
190End:
191*/