act_playing
[disorder] / server / actions.c
CommitLineData
bca4e2b7
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2008 Richard Kettlewell
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 */
20
21#include <config.h>
22#include "types.h"
23
448d3570
RK
24#include "actions.h"
25#include "lookups.h"
26
bca4e2b7
RK
27/** @brief Login cookie */
28char *login_cookie;
29
448d3570
RK
30/* 'playing' and 'manage' just add a Refresh: header */
31static void act_playing(void) {
32 long refresh = config->refresh;
33 long length;
34 time_t now, fin;
35 char *url;
36
37 lookups(DC_PLAYING|DC_QUEUE|DC_ENABLED|DC_RANDOM_ENABLED);
38 if(playing
39 && playing->state == playing_started /* i.e. not paused */
40 && !disorder_length(client, playing->track, &length)
41 && length
42 && playing->sofar >= 0) {
43 /* Try to put the next refresh at the start of the next track. */
44 time(&now);
45 fin = now + length - playing->sofar + config->gap;
46 if(now + refresh > fin)
47 refresh = fin - now;
48 }
49 if(queue && queue->state == playing_isscratch) {
50 /* next track is a scratch, don't leave more than the inter-track gap */
51 if(refresh > config->gap)
52 refresh = config->gap;
53 }
54 if(!playing
55 && ((queue
56 && queue->state != playing_random)
57 || random_enabled)
58 && enabled) {
59 /* no track playing but playing is enabled and there is something coming
60 * up, must be in a gap */
61 if(refresh > config->gap)
62 refresh = config->gap;
63 }
64 if((action = cgi_get("action")))
65 url = cgi_makeurl(config->url, "action", action, (char *)0);
66 else
67 url = config->url;
68 if(printf("Content-Type: text/html\n"
69 "Refresh: %ld;url=%s\n"
70 /* TODO cookie */
71 "\n",
72 refresh, url) < 0)
73 fatal(errno, "error writing to stdout");
74 disorder_cgi_expand(action ? action : "playing");
75}
76
bca4e2b7
RK
77/** @brief Table of actions */
78static const struct action {
79 /** @brief Action name */
80 const char *name;
81 /** @brief Action handler */
82 void (*handler)(void);
83} actions[] = {
84 { "confirm", act_confirm },
85 { "disable", act_disable },
86 { "edituser", act_edituser },
87 { "enable", act_enable },
88 { "login", act_login },
89 { "logout", act_logout },
448d3570 90 { "manage", act_playing },
bca4e2b7
RK
91 { "move", act_move },
92 { "pause", act_pause },
93 { "play", act_play },
94 { "playing", act_playing },
95 { "prefs", act_prefs },
96 { "random-disable", act_random_disable },
97 { "random-enable", act_random_enable },
98 { "register", act_register },
99 { "reminder", act_reminder },
100 { "remove", act_remove },
101 { "resume", act_resume },
102 { "scratch", act_scratch },
103 { "volume", act_volume },
104};
105
106/** @brief Expand a template
107 * @param name Base name of template, or NULL to consult CGI args
108 */
109void disorder_cgi_expand(const char *name) {
110 const char *p;
111
112 /* For unknown actions check that they aren't evil */
113 for(p = name; *p && isalnum((unsigned char)*p); ++p)
114 ;
115 if(*p)
116 fatal(0, "invalid action name '%s'", action);
117 byte_xasprintf((char **)&p, "%s.tmpl", action);
118 if(mx_expand_file(p, sink_stdio(stdout), 0) == -1
119 || fflush(stdout) < 0)
120 fatal(errno, "error writing to stdout");
121}
122
123/** @brief Execute a web action
124 * @param action Action to perform, or NULL to consult CGI args
125 *
126 * If no recognized action is specified then 'playing' is assumed.
127 */
128void disorder_cgi_action(const char *action) {
129 int n;
130 char *s;
131
132 /* Consult CGI args if caller had no view */
133 if(!action)
134 action = cgi_get("action");
135 /* Pick a default if nobody cares at all */
136 if(!action) {
137 /* We allow URLs which are just c=... in order to keep confirmation URLs,
138 * which are user-facing, as short as possible. Actually we could lose the
139 * c= for this... */
140 if(cgi_get("c"))
141 action = "confirm";
142 else
143 action = "playing";
144 }
145 if((n = TABLE_FIND(actions, struct action, name, action)) >= 0)
146 /* Its a known action */
147 actions[n].handler();
448d3570 148 else {
bca4e2b7 149 /* Just expand the template */
448d3570
RK
150 if(printf("Content-Type: text/html\n"
151 /* TODO cookie */
152 "\n") < 0)
153 fatal(errno, "error writing to stdout");
bca4e2b7 154 disorder_cgi_expand(action);
448d3570 155 }
bca4e2b7
RK
156}
157
158/** @brief Generate an error page */
159void disorder_cgi_error(const char *msg, ...) {
160 va_list ap;
161
162 va_start(ap, msg);
163 byte_xvasprintf(&error_string, msg, ap);
164 va_end(ap);
165 disorder_cgi_expand("error");
166}
167
168/** @brief Log in as the current user or guest if none */
169void disorder_cgi_login(dcgi_state *ds, struct sink *output) {
170 /* Junk old data */
171 disorder_macros_reset();
172 /* Reconnect */
173 if(disorder_connect_cookie(client, login_cookie)) {
174 disorder_cgi_error("Cannot connect to server");
175 exit(0);
176 }
177 /* If there was a cookie but it went bad, we forget it */
178 if(login_cookie && !strcmp(disorder_user(>client), "guest"))
179 login_cookie = 0;
180}
181
182/*
183Local Variables:
184c-basic-offset:2
185comment-column:40
186fill-column:79
187indent-tabs-mode:nil
188End:
189*/